package org.audit4j.core.schedule; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.Future; import javax.enterprise.concurrent.ManagedExecutors; import javax.enterprise.concurrent.ManagedTask; /** * Adapter that takes a {@code java.util.concurrent.Executor} and exposes a * Spring {@link org.audit4j.schedule.springframework.core.task.TaskExecutor} for it. Also * detects an extended {@code java.util.concurrent.ExecutorService}, adapting * the {@link org.audit4j.schedule.springframework.core.task.AsyncTaskExecutor} interface * accordingly. * * <p> * Autodetects a JSR-236 * {@link javax.enterprise.concurrent.ManagedExecutorService} in order to expose * {@link javax.enterprise.concurrent.ManagedTask} adapters for it, exposing a * long-running hint based on {@link SchedulingAwareRunnable} and an identity * name based on the given Runnable/Callable's {@code toString()}. For JSR-236 * style lookup in a Java EE 7 environment, consider using * {@link DefaultManagedTaskExecutor}. * * <p> * Note that there is a pre-built {@link ThreadPoolTaskExecutor} that allows for * defining a {@link java.util.concurrent.ThreadPoolExecutor} in bean style, * exposing it as a Spring {@link org.audit4j.schedule.springframework.core.task.TaskExecutor} * directly. This is a convenient alternative to a raw ThreadPoolExecutor * definition with a separate definition of the present adapter class. * * @author Juergen Hoeller * @since 2.0 * @see java.util.concurrent.Executor * @see java.util.concurrent.ExecutorService * @see java.util.concurrent.ThreadPoolExecutor * @see java.util.concurrent.Executors * @see DefaultManagedTaskExecutor * @see ThreadPoolTaskExecutor */ public class ConcurrentTaskExecutor implements AsyncTaskExecutor, SchedulingTaskExecutor { /** The managed executor service class. */ private static Class<?> managedExecutorServiceClass; static { try { managedExecutorServiceClass = Class.forName("javax.enterprise.concurrent.ManagedExecutorService"); } catch (ClassNotFoundException ex) { // JSR-236 API not available... managedExecutorServiceClass = null; } } /** The concurrent executor. */ private Executor concurrentExecutor; /** The adapted executor. */ private TaskExecutorAdapter adaptedExecutor; /** * Create a new ConcurrentTaskExecutor, using a single thread executor as * default. * * @see java.util.concurrent.Executors#newSingleThreadExecutor() */ public ConcurrentTaskExecutor() { setConcurrentExecutor(null); } /** * Create a new ConcurrentTaskExecutor, using the given. * * @param concurrentExecutor the {@link java.util.concurrent.Executor} to delegate to * {@link java.util.concurrent.Executor}. * <p> * Autodetects a JSR-236 * {@link javax.enterprise.concurrent.ManagedExecutorService} in order to * expose {@link javax.enterprise.concurrent.ManagedTask} adapters for it. */ public ConcurrentTaskExecutor(Executor concurrentExecutor) { setConcurrentExecutor(concurrentExecutor); } /** * Specify the {@link java.util.concurrent.Executor} to delegate to. * <p> * Autodetects a JSR-236 * * @param concurrentExecutor the new concurrent executor * {@link javax.enterprise.concurrent.ManagedExecutorService} in order to * expose {@link javax.enterprise.concurrent.ManagedTask} adapters for it. */ public final void setConcurrentExecutor(Executor concurrentExecutor) { if (concurrentExecutor != null) { this.concurrentExecutor = concurrentExecutor; if (managedExecutorServiceClass != null && managedExecutorServiceClass.isInstance(concurrentExecutor)) { this.adaptedExecutor = new ManagedTaskExecutorAdapter(concurrentExecutor); } else { this.adaptedExecutor = new TaskExecutorAdapter(concurrentExecutor); } } else { this.concurrentExecutor = Executors.newSingleThreadExecutor(); this.adaptedExecutor = new TaskExecutorAdapter(this.concurrentExecutor); } } /** * Return the {@link java.util.concurrent.Executor} that this adapter * delegates to. * * @return the concurrent executor */ public final Executor getConcurrentExecutor() { return this.concurrentExecutor; } /** * {@inheritDoc} * * @see org.audit4j.core.schedule.TaskExecutor#execute(java.lang.Runnable) * */ @Override public void execute(Runnable task) { this.adaptedExecutor.execute(task); } /** * {@inheritDoc} * * @see org.audit4j.core.schedule.AsyncTaskExecutor#execute(java.lang.Runnable, long) * */ @Override public void execute(Runnable task, long startTimeout) { this.adaptedExecutor.execute(task, startTimeout); } /** * {@inheritDoc} * * @see org.audit4j.core.schedule.AsyncTaskExecutor#submit(java.lang.Runnable) * */ @Override public Future<?> submit(Runnable task) { return this.adaptedExecutor.submit(task); } /** * {@inheritDoc} * * @see org.audit4j.core.schedule.AsyncTaskExecutor#submit(java.util.concurrent.Callable) * */ @Override public <T> Future<T> submit(Callable<T> task) { return this.adaptedExecutor.submit(task); } /** * This task executor prefers short-lived work units. * * @return true, if successful */ @Override public boolean prefersShortLivedTasks() { return true; } /** * TaskExecutorAdapter subclass that wraps all provided Runnables and * Callables with a JSR-236 ManagedTask, exposing a long-running hint based * on {@link SchedulingAwareRunnable} and an identity name based on the * task's {@code toString()} representation. * * @author <a href="mailto:janith3000@gmail.com">Janith Bandara</a> * @since */ private static class ManagedTaskExecutorAdapter extends TaskExecutorAdapter { /** * Instantiates a new managed task executor adapter. * * @param concurrentExecutor the concurrent executor */ public ManagedTaskExecutorAdapter(Executor concurrentExecutor) { super(concurrentExecutor); } /** * {@inheritDoc} * * @see org.audit4j.core.schedule.TaskExecutorAdapter#execute(java.lang.Runnable) * */ @Override public void execute(Runnable task) { super.execute(ManagedTaskBuilder.buildManagedTask(task, task.toString())); } /** * {@inheritDoc} * * @see org.audit4j.core.schedule.TaskExecutorAdapter#submit(java.lang.Runnable) * */ @Override public Future<?> submit(Runnable task) { return super.submit(ManagedTaskBuilder.buildManagedTask(task, task.toString())); } /** * {@inheritDoc} * * @see org.audit4j.core.schedule.TaskExecutorAdapter#submit(java.util.concurrent.Callable) * */ @Override public <T> Future<T> submit(Callable<T> task) { return super.submit(ManagedTaskBuilder.buildManagedTask(task, task.toString())); } } /** * Delegate that wraps a given Runnable/Callable with a JSR-236 ManagedTask, * exposing a long-running hint based on {@link SchedulingAwareRunnable} and * a given identity name. * * @author <a href="mailto:janith3000@gmail.com">Janith Bandara</a> * @since */ protected static class ManagedTaskBuilder { /** * Builds the managed task. * * @param task the task * @param identityName the identity name * @return the runnable */ public static Runnable buildManagedTask(Runnable task, String identityName) { Map<String, String> properties = new HashMap<String, String>(2); if (task instanceof SchedulingAwareRunnable) { properties.put(ManagedTask.LONGRUNNING_HINT, Boolean.toString(((SchedulingAwareRunnable) task).isLongLived())); } properties.put(ManagedTask.IDENTITY_NAME, identityName); return ManagedExecutors.managedTask(task, properties, null); } /** * Builds the managed task. * * @param <T> the generic type * @param task the task * @param identityName the identity name * @return the callable */ public static <T> Callable<T> buildManagedTask(Callable<T> task, String identityName) { Map<String, String> properties = new HashMap<String, String>(1); properties.put(ManagedTask.IDENTITY_NAME, identityName); return ManagedExecutors.managedTask(task, properties, null); } } }