All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.threads.JBossExecutors Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 34.0.0.Final
Show newest version
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2017 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jboss.threads;

import java.lang.reflect.Field;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ScheduledExecutorService;
import java.util.Collection;
import java.security.PrivilegedAction;
import java.security.AccessController;
import java.security.Permission;
import org.jboss.logging.Logger;
import org.wildfly.common.Assert;
import sun.misc.Unsafe;

/**
 * JBoss thread- and executor-related utility and factory methods.
 */
public final class JBossExecutors {

    private static final Logger THREAD_ERROR_LOGGER = Logger.getLogger("org.jboss.threads.errors");

    private JBossExecutors() {}

    private static final RuntimePermission MODIFY_THREAD_PERMISSION = new RuntimePermission("modifyThread");
    private static final RuntimePermission COPY_CONTEXT_CLASSLOADER_PERMISSION = new RuntimePermission("copyClassLoader");

    private static final DirectExecutorService DIRECT_EXECUTOR_SERVICE = new DelegatingDirectExecutorService(SimpleDirectExecutor.INSTANCE);
    private static final DirectExecutorService REJECTING_EXECUTOR_SERVICE = new DelegatingDirectExecutorService(RejectingExecutor.INSTANCE);
    private static final DirectExecutorService DISCARDING_EXECUTOR_SERVICE = new DelegatingDirectExecutorService(DiscardingExecutor.INSTANCE);

    @Deprecated
    private static final BlockingExecutor BLOCKING_DIRECT_EXECUTOR = new DelegatingDirectBlockingExecutor(SimpleDirectExecutor.INSTANCE);
    @Deprecated
    private static final BlockingExecutor BLOCKING_REJECTING_EXECUTOR = new DelegatingDirectBlockingExecutor(RejectingExecutor.INSTANCE);
    @Deprecated
    private static final BlockingExecutor BLOCKING_DISCARDING_EXECUTOR = new DelegatingDirectBlockingExecutor(DiscardingExecutor.INSTANCE);

    // ==================================================
    // DIRECT EXECUTORS
    // ==================================================

    /**
     * Get the direct executor.  This executor will immediately run any task it is given, and propagate back any
     * run-time exceptions thrown.
     *
     * @return the direct executor instance
     */
    public static DirectExecutor directExecutor() {
        return SimpleDirectExecutor.INSTANCE;
    }

    /**
     * Get the direct executor service.  This executor will immediately run any task it is given, and propagate back any
     * run-time exceptions thrown.  It cannot be shut down.
     *
     * @return the direct executor service instance
     */
    public static DirectExecutorService directExecutorService() {
        return DIRECT_EXECUTOR_SERVICE;
    }

    /**
     * Get the rejecting executor.  This executor will reject any task submitted to it.
     *
     * @return the rejecting executor instance
     */
    public static DirectExecutor rejectingExecutor() {
        return RejectingExecutor.INSTANCE;
    }

    /**
     * Get a rejecting executor.  This executor will reject any task submitted to it with the given message.
     *
     * @param message the reject message
     * @return the rejecting executor instance
     */
    public static DirectExecutor rejectingExecutor(final String message) {
        return new RejectingExecutor(message);
    }

    /**
     * Get the rejecting executor service.  This executor will reject any task submitted to it.  It cannot be shut down.
     *
     * @return the rejecting executor service instance
     */
    public static DirectExecutorService rejectingExecutorService() {
        return REJECTING_EXECUTOR_SERVICE;
    }

    /**
     * Get the rejecting executor service.  This executor will reject any task submitted to it with the given message.
     * It cannot be shut down.
     *
     * @param message the reject message
     * @return the rejecting executor service instance
     */
    public static DirectExecutorService rejectingExecutorService(final String message) {
        return protectedDirectExecutorService(rejectingExecutor(message));
    }

    /**
     * Get the discarding executor.  This executor will silently discard any task submitted to it.
     *
     * @return the discarding executor instance
     */
    public static DirectExecutor discardingExecutor() {
        return DiscardingExecutor.INSTANCE;
    }

    /**
     * Get the discarding executor service.  This executor will silently discard any task submitted to it.  It cannot
     * be shut down.
     *
     * @return the discarding executor service instance
     */
    public static DirectExecutorService discardingExecutorService() {
        return DISCARDING_EXECUTOR_SERVICE;
    }

    /**
     * Create a direct executor which runs with the privileges given by the current access control context.
     *
     * @param delegate the executor to delegate to at the privileged level
     * @return the new direct executor
     */
    public static DirectExecutor privilegedExecutor(final DirectExecutor delegate) {
        return new PrivilegedExecutor(delegate);
    }

    /**
     * Create a direct executor which runs tasks with the given context class loader.
     *
     * @param delegate the executor to delegate to
     * @param taskClassLoader the context class loader to use
     * @return the new direct executor
     */
    public static DirectExecutor contextClassLoaderExecutor(final DirectExecutor delegate, final ClassLoader taskClassLoader) {
        return new ContextClassLoaderExecutor(taskClassLoader, delegate);
    }

    /**
     * Create a direct executor which changes the thread name for the duration of a task.
     *
     * @param delegate the executor to delegate to
     * @param newName the thread name to use
     * @return the new direct executor
     */
    public static DirectExecutor threadNameExecutor(final DirectExecutor delegate, final String newName) {
        return new ThreadNameExecutor(newName, delegate);
    }

    /**
     * Create a direct executor which changes the thread name for the duration of a task using a formatted name.
     * The thread must be a {@link JBossThread}.
     *
     * @param delegate the executor to delegate to
     * @param newName the thread name to use
     * @return the new direct executor
     */
    public static DirectExecutor threadFormattedNameExecutor(final DirectExecutor delegate, final String newName) {
        return new ThreadFormattedNameExecutor(newName, delegate);
    }

    /**
     * Create a direct executor which adds a note to the thread name for the duration of a task.
     *
     * @param delegate the executor to delegate to
     * @param notation the note to use
     * @return the new direct executor
     */
    public static DirectExecutor threadNameNotateExecutor(final DirectExecutor delegate, final String notation) {
        return new ThreadNameNotatingExecutor(notation, delegate);
    }

    /**
     * Create a direct executor which consumes and logs errors that are thrown.
     *
     * @param delegate the executor to delegate to
     * @param log the logger to which exceptions are written at the {@code error} level
     * @return the new direct executor
     */
    public static DirectExecutor exceptionLoggingExecutor(final DirectExecutor delegate, final Logger log) {
        return new ExceptionLoggingExecutor(delegate, log);
    }

    /**
     * Create a direct executor which consumes and logs errors that are thrown.
     *
     * @param delegate the executor to delegate to
     * @param log the logger to which exceptions are written
     * @param level the level at which to log exceptions
     * @return the new direct executor
     */
    public static DirectExecutor exceptionLoggingExecutor(final DirectExecutor delegate, final Logger log, final Logger.Level level) {
        return new ExceptionLoggingExecutor(delegate, log, level);
    }

    /**
     * Create a direct executor which consumes and logs errors that are thrown to the default thread error category
     * {@code "org.jboss.threads.errors"}.
     *
     * @param delegate the executor to delegate to
     * @return the new direct executor
     */
    public static DirectExecutor exceptionLoggingExecutor(final DirectExecutor delegate) {
        return exceptionLoggingExecutor(delegate, THREAD_ERROR_LOGGER);
    }

    /**
     * Create a direct executor which delegates tasks to the given executor, and then clears all thread-local
     * data after each task completes (regardless of outcome).  You must have the {@link RuntimePermission}{@code ("modifyThread")}
     * permission to use this method.
     *
     * @param delegate the delegate direct executor
     * @return a resetting executor
     * @throws SecurityException if the caller does not have the {@link RuntimePermission}{@code ("modifyThread")} permission
     */
    public static DirectExecutor resettingExecutor(final DirectExecutor delegate) throws SecurityException {
        return cleanupExecutor(delegate, threadLocalResetter());
    }

    /**
     * Create an executor which runs the given initialization task before running its given task.
     *
     * @param delegate the delegate direct executor
     * @param initializer the initialization task
     * @return an initializing executor
     */
    public static DirectExecutor initializingExecutor(final DirectExecutor delegate, final Runnable initializer) {
        return new InitializingExecutor(initializer, delegate);
    }

    /**
     * Create an executor which runs the given cleanup task after running its given task.
     *
     * @param delegate the delegate direct executor
     * @param cleaner the cleanup task
     * @return an initializing executor
     */
    public static DirectExecutor cleanupExecutor(final DirectExecutor delegate, final Runnable cleaner) {
        return new CleanupExecutor(cleaner, delegate);
    }

    // ==================================================
    // DIRECT BLOCKING EXECUTORS
    // ==================================================

    /**
     * Get an executor which executes tasks in the current thread, which implements {@code BlockingExecutor}.
     *
     * @return the blocking direct executor
     */
    @Deprecated
    public static BlockingExecutor blockingDirectExecutor() {
        return BLOCKING_DIRECT_EXECUTOR;
    }

    /**
     * Get an executor which discards all tasks, which implements {@code BlockingExecutor}.
     *
     * @return the executor
     */
    @Deprecated
    public static BlockingExecutor blockingDiscardingExecutor() {
        return BLOCKING_DISCARDING_EXECUTOR;
    }

    /**
     * Get an executor which rejects all tasks, which implements {@code BlockingExecutor}.
     *
     * @return the executor
     */
    @Deprecated
    public static BlockingExecutor blockingRejectingExecutor() {
        return BLOCKING_REJECTING_EXECUTOR;
    }

    // ==================================================
    // EXECUTORS
    // ==================================================

    /**
     * An executor which delegates to another executor, wrapping each task in a task wrapper.
     *
     * @param taskWrapper the task wrapper
     * @param delegate the delegate executor
     * @return a wrapping executor
     */
    public static Executor wrappingExecutor(final DirectExecutor taskWrapper, final Executor delegate) {
        return executor(wrappingExecutor(delegate), taskWrapper);
    }

    /**
     * An executor which delegates to the given direct executor, but implements the blocking executor interface.
     * Since direct executors always execute tasks in the current thread, no blocking is possible; therefore the
     * methods of BlockingExecutors always succeed or fail instantly.
     *
     * @param delegate the delegate direct executor
     * @return the blocking executor
     */
    @Deprecated
    public static BlockingExecutor directBlockingExecutor(final DirectExecutor delegate) {
        return new DelegatingDirectBlockingExecutor(delegate);
    }

    /**
     * Create a wrapping executor for a delegate executor which creates an {@link #executorTask(DirectExecutor, Runnable)} for
     * each task.
     *
     * @param delegate the delegate executor
     * @return the wrapping executor
     */
    public static WrappingExecutor wrappingExecutor(final Executor delegate) {
        return new DelegatingWrappingExecutor(delegate);
    }

    /**
     * An executor which delegates to a wrapping executor, wrapping each task in a task wrapper.
     *
     * @param delegate the delegate executor
     * @param taskWrapper the task wrapper
     * @return a wrapping executor
     */
    public static Executor executor(final WrappingExecutor delegate, final DirectExecutor taskWrapper) {
        return new DelegatingWrappedExecutor(delegate, taskWrapper);
    }

    /**
     * Create an executor that executes each task in a new thread.
     *
     * @param factory the thread factory to use
     * @return the executor
     * @deprecated Use {@link EnhancedQueueExecutor} instead.
     */
    @Deprecated
    public static BlockingExecutor threadFactoryExecutor(final ThreadFactory factory) {
        return new ThreadFactoryExecutor(factory, Integer.MAX_VALUE, false, directExecutor());
    }

    /**
     * Create an executor that executes each task in a new thread.  By default up to the given number of threads may run
     * concurrently, after which new tasks will be rejected.
     *
     * @param factory the thread factory to use
     * @param maxThreads the maximum number of allowed threads
     * @return the executor
     * @deprecated Use {@link EnhancedQueueExecutor} instead.
     */
    @Deprecated
    public static BlockingExecutor threadFactoryExecutor(final ThreadFactory factory, final int maxThreads) {
        return new ThreadFactoryExecutor(factory, maxThreads, false, directExecutor());
    }

    /**
     * Create an executor that executes each task in a new thread.  By default up to the given number of threads may run
     * concurrently, after which the caller will block or new tasks will be rejected, according to the setting of the
     * {@code blocking} parameter.
     *
     * @param factory the thread factory to use
     * @param maxThreads the maximum number of allowed threads
     * @param blocking {@code true} if the submitter should block when the maximum number of threads has been reached
     * @return the executor
     * @deprecated Use {@link EnhancedQueueExecutor} instead.
     */
    @Deprecated
    public static BlockingExecutor threadFactoryExecutor(final ThreadFactory factory, final int maxThreads, final boolean blocking) {
        return new ThreadFactoryExecutor(factory, maxThreads, blocking, directExecutor());
    }

    /**
     * Create an executor that executes each task in a new thread.  By default up to the given number of threads may run
     * concurrently, after which the caller will block or new tasks will be rejected, according to the setting of the
     * {@code blocking} parameter.
     *
     * @param factory the thread factory to use
     * @param maxThreads the maximum number of allowed threads
     * @param blocking {@code true} if the submitter should block when the maximum number of threads has been reached
     * @param taskExecutor the executor which should run each task
     * @return the executor
     * @deprecated Use {@link EnhancedQueueExecutor} instead.
     */
    @Deprecated
    public static BlockingExecutor threadFactoryExecutor(final ThreadFactory factory, final int maxThreads, final boolean blocking, final DirectExecutor taskExecutor) {
        return new ThreadFactoryExecutor(factory, maxThreads, blocking, taskExecutor);
    }

    // ==================================================
    // REJECTED EXECUTION HANDLERS
    // ==================================================

    private static final RejectedExecutionHandler ABORT_POLICY = new ThreadPoolExecutor.AbortPolicy();
    private static final RejectedExecutionHandler CALLER_RUNS_POLICY = new ThreadPoolExecutor.CallerRunsPolicy();
    private static final RejectedExecutionHandler DISCARD_OLDEST_POLICY = new ThreadPoolExecutor.DiscardOldestPolicy();
    private static final RejectedExecutionHandler DISCARD_POLICY = new ThreadPoolExecutor.DiscardPolicy();

    /**
     * Get the abort policy for a {@link java.util.concurrent.ThreadPoolExecutor}.
     *
     * @return the abort policy
     * @see java.util.concurrent.ThreadPoolExecutor.AbortPolicy
     */
    public static RejectedExecutionHandler abortPolicy() {
        return ABORT_POLICY;
    }

    /**
     * Get the caller-runs policy for a {@link java.util.concurrent.ThreadPoolExecutor}.
     *
     * @return the caller-runs policy
     * @see java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy
     */
    public static RejectedExecutionHandler callerRunsPolicy() {
        return CALLER_RUNS_POLICY;
    }

    /**
     * Get the discard-oldest policy for a {@link java.util.concurrent.ThreadPoolExecutor}.
     *
     * @return the discard-oldest policy
     * @see java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy
     */
    public static RejectedExecutionHandler discardOldestPolicy() {
        return DISCARD_OLDEST_POLICY;
    }

    /**
     * Get the discard policy for a {@link java.util.concurrent.ThreadPoolExecutor}.
     *
     * @return the discard policy
     * @see java.util.concurrent.ThreadPoolExecutor.DiscardPolicy
     */
    public static RejectedExecutionHandler discardPolicy() {
        return DISCARD_POLICY;
    }

    /**
     * Get a handoff policy for a {@link java.util.concurrent.ThreadPoolExecutor}.  The returned instance will
     * delegate to another executor in the event that the task is rejected.
     *
     * @param target the target executor
     * @return the new handoff policy implementation
     */
    public static RejectedExecutionHandler handoffPolicy(final Executor target) {
        return new HandoffRejectedExecutionHandler(target);
    }

    // ==================================================
    // PROTECTED EXECUTOR SERVICE WRAPPERS
    // ==================================================

    @Deprecated
    public static BlockingExecutor protectedBlockingExecutor(final BlockingExecutor target) {
        return new DelegatingBlockingExecutor(target);
    }

    /**
     * Wrap an executor with an {@code ExecutorService} instance which supports all the features of {@code ExecutorService}
     * except for shutting down the executor.
     *
     * @param target the target executor
     * @return the executor service
     */
    public static ExecutorService protectedExecutorService(final Executor target) {
        return new DelegatingExecutorService(target);
    }

    /**
     * Wrap a direct executor with an {@code DirectExecutorService} instance which supports all the features of {@code ExecutorService}
     * except for shutting down the executor.
     *
     * @param target the target executor
     * @return the executor service
     */
    public static DirectExecutorService protectedDirectExecutorService(final DirectExecutor target) {
        return new DelegatingDirectExecutorService(target);
    }

    /**
     * Wrap a scheduled executor with a {@code ScheduledExecutorService} instance which supports all the features of
     * {@code ScheduledExecutorService} except for shutting down the executor.
     *
     * @param target the target executor
     * @return the executor service
     */
    public static ScheduledExecutorService protectedScheduledExecutorService(final ScheduledExecutorService target) {
        return new DelegatingScheduledExecutorService(target);
    }

    /**
     * Wrap a blocking executor with an {@code BlockingExecutorService} instance which supports all the features of
     * {@code BlockingExecutorService} except for shutting down the executor.
     *
     * @param target the target executor
     * @return the executor service
     */
    @Deprecated
    public static BlockingExecutorService protectedBlockingExecutorService(final BlockingExecutor target) {
        return new DelegatingBlockingExecutorService(target);
    }

    // ==================================================
    // THREAD FACTORIES
    // ==================================================

    /**
     * Create a thread factory which resets all thread-local storage and delegates to the given thread factory.
     * You must have the {@link RuntimePermission}{@code ("modifyThread")} permission to use this method.
     *
     * @param delegate the delegate thread factory
     * @return the resetting thread factory
     * @throws SecurityException if the caller does not have the {@link RuntimePermission}{@code ("modifyThread")}
     * permission
     */
    public static ThreadFactory resettingThreadFactory(final ThreadFactory delegate) throws SecurityException {
        return wrappingThreadFactory(resettingExecutor(directExecutor()), delegate);
    }

    /**
     * Creates a thread factory which executes the thread task via the given task wrapping executor.
     *
     * @param taskWrapper the task wrapping executor
     * @param delegate the delegate thread factory
     * @return the wrapping thread factory
     */
    public static ThreadFactory wrappingThreadFactory(final DirectExecutor taskWrapper, final ThreadFactory delegate) {
        return new WrappingThreadFactory(delegate, taskWrapper);
    }

    private static final Runnable TCCL_RESETTER = new Runnable() {
        public void run() {
            Thread.currentThread().setContextClassLoader(null);
        }

        public String toString() {
            return "ContextClassLoader-resetting Runnable";
        }
    };

    // ==================================================
    // RUNNABLES
    // ==================================================

    private static final Runnable NULL_RUNNABLE = NullRunnable.getInstance();
    private static final Runnable THREAD_LOCAL_RESETTER;

    /**
     * Get the null runnable which does nothing.
     *
     * @return the null runnable
     */
    public static Runnable nullRunnable() {
        return NULL_RUNNABLE;
    }

    /**
     * Get a {@code Runnable} which, when executed, clears the thread-local storage of the calling thread.
     * You must have the {@link RuntimePermission}{@code ("modifyThread")}
     * permission to use this method.
     *
     * @return the runnable
     * @throws SecurityException if the caller does not have the {@link RuntimePermission}{@code ("modifyThread")}
     * permission
     */
    public static Runnable threadLocalResetter() throws SecurityException {
        checkAccess(MODIFY_THREAD_PERMISSION);
        return THREAD_LOCAL_RESETTER;
    }

    /**
     * Get a {@code Runnable} which, when executed, clears the thread context class loader (if the caller has sufficient
     * privileges).
     *
     * @return the runnable
     */
    public static Runnable contextClassLoaderResetter() {
        return TCCL_RESETTER;
    }

    /**
     * Get a task that runs the given task through the given direct executor.
     *
     * @param executor the executor to run the task through
     * @param task the task to run
     * @return an encapsulating task
     */
    public static Runnable executorTask(final DirectExecutor executor, final Runnable task) {
        return new ExecutorTask(executor, task);
    }

    /**
     * Create a task that is a composite of several other tasks.
     *
     * @param runnables the tasks
     * @return the composite task
     */
    public static Runnable compositeTask(final Runnable... runnables) {
        return new CompositeTask(runnables.clone());
    }

    /**
     * Create a task that delegates to the given task, preserving the context classloader which was in effect when
     * this method was invoked.
     *
     * @param delegate the delegate runnable
     * @return the wrapping runnable
     * @throws SecurityException if a security manager exists and the caller does not have the {@code "copyClassLoader"}
     * {@link RuntimePermission}.
     */
    public static Runnable classLoaderPreservingTask(final Runnable delegate) throws SecurityException {
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkPermission(COPY_CONTEXT_CLASSLOADER_PERMISSION);
        }
        return classLoaderPreservingTaskUnchecked(delegate);
    }

    static final ClassLoader SAFE_CL;

    static {
        ClassLoader safeClassLoader = JBossExecutors.class.getClassLoader();
        if (safeClassLoader == null) {
            safeClassLoader = ClassLoader.getSystemClassLoader();
        }
        if (safeClassLoader == null) {
            safeClassLoader = new ClassLoader() {
            };
        }
        SAFE_CL = safeClassLoader;
    }

    static Runnable classLoaderPreservingTaskUnchecked(final Runnable delegate) {
        Assert.checkNotNullParam("delegate", delegate);
        return new ContextClassLoaderSavingRunnable(getContextClassLoader(Thread.currentThread()), delegate);
    }

    static final Unsafe unsafe;

    static final long contextClassLoaderOffs;

    static {
        unsafe = AccessController.doPrivileged(new PrivilegedAction() {
            public Unsafe run() {
                try {
                    final Field field = Unsafe.class.getDeclaredField("theUnsafe");
                    field.setAccessible(true);
                    return (Unsafe) field.get(null);
                } catch (IllegalAccessException e) {
                    throw new IllegalAccessError(e.getMessage());
                } catch (NoSuchFieldException e) {
                    throw new NoSuchFieldError(e.getMessage());
                }
            }
        });
        try {
            contextClassLoaderOffs = unsafe.objectFieldOffset(Thread.class.getDeclaredField("contextClassLoader"));
        } catch (NoSuchFieldException e) {
            throw new NoSuchFieldError(e.getMessage());
        }
        THREAD_LOCAL_RESETTER = ThreadLocalResetter.getInstance();
    }

    /**
     * Privileged method to get the context class loader of the given thread.
     *
     * @param thread the thread to introspect
     * @return the context class loader
     */
    static ClassLoader getContextClassLoader(final Thread thread) {
        return (ClassLoader) unsafe.getObject(thread, contextClassLoaderOffs);
    }

    /**
     * Privileged method to get and set the context class loader of the given thread.
     *
     * @param thread the thread to introspect
     * @param newClassLoader the new context class loader
     * @return the old context class loader
     */
    static ClassLoader getAndSetContextClassLoader(final Thread thread, final ClassLoader newClassLoader) {
        try {
            return getContextClassLoader(thread);
        } finally {
            setContextClassLoader(thread, newClassLoader);
        }
    }

    /**
     * Privileged method to set the context class loader of the given thread.
     *
     * @param thread the thread to introspect
     * @param classLoader the new context class loader
     */
    static void setContextClassLoader(final Thread thread, final ClassLoader classLoader) {
        unsafe.putObject(thread, contextClassLoaderOffs, classLoader);
    }

    /**
     * Privileged method to clear the context class loader of the given thread to a safe non-{@code null} value.
     *
     * @param thread the thread to introspect
     */
    static void clearContextClassLoader(final Thread thread) {
        unsafe.putObject(thread, contextClassLoaderOffs, SAFE_CL);
    }

    /**
     * Create a task that is a composite of several other tasks.
     *
     * @param runnables the tasks
     * @return the composite task
     */
    public static Runnable compositeTask(final Collection runnables) {
        return new CompositeTask(runnables.toArray(new Runnable[runnables.size()]));
    }

    static void checkAccess(Permission permission) {
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkPermission(permission);
        }
    }

    // ==================================================
    // UNCAUGHT EXCEPTION HANDLERS
    // ==================================================

    /**
     * Get an uncaught exception handler which logs to the given logger.
     *
     * @param log the logger
     * @return the handler
     */
    public static Thread.UncaughtExceptionHandler loggingExceptionHandler(final Logger log) {
        return new LoggingUncaughtExceptionHandler(log);
    }

    /**
     * Get an uncaught exception handler which logs to the given logger.
     *
     * @param categoryName the name of the logger category to log to
     * @return the handler
     */
    public static Thread.UncaughtExceptionHandler loggingExceptionHandler(final String categoryName) {
        return new LoggingUncaughtExceptionHandler(Logger.getLogger(categoryName));
    }

    private static final Thread.UncaughtExceptionHandler LOGGING_HANDLER = loggingExceptionHandler(THREAD_ERROR_LOGGER);

    /**
     * Get an uncaught exception handler which logs to the default error logger.
     *
     * @return the handler
     */
    public static Thread.UncaughtExceptionHandler loggingExceptionHandler() {
        return LOGGING_HANDLER;
    }

    private static  void logError(final R runnable, final Throwable t, final String method) {
        THREAD_ERROR_LOGGER.errorf(t, "Notifier %s() method invocation failed for task %s", method, runnable);
    }

    private static  void started(TaskNotifier notifier, R runnable, A attachment) {
        try {
            notifier.started(runnable, attachment);
        } catch (Throwable t) {
            logError(runnable, t, "started");
        }
    }

    private static  void finished(TaskNotifier notifier, R runnable, A attachment) {
        try {
            notifier.finished(runnable, attachment);
        } catch (Throwable t) {
            logError(runnable, t, "finished");
        }
    }

    private static  void failed(TaskNotifier notifier, Throwable reason, R runnable, A attachment) {
        try {
            notifier.failed(runnable, reason, attachment);
        } catch (Throwable t) {
            logError(runnable, t, "failed");
        }
    }

    /**
     * Run a task through the given direct executor, invoking the given notifier with the given attachment.
     *
     * @param task the task
     * @param directExecutor the executor
     * @param notifier the notifier
     * @param attachment the attachment
     * @param  the task type
     * @param  the attachment type
     */
    public static  void run(R task, DirectExecutor directExecutor, TaskNotifier notifier, A attachment) {
        started(notifier, task, attachment);
        boolean ok = false;
        try {
            directExecutor.execute(task);
            ok = true;
        } catch (RuntimeException t) {
            failed(notifier, t, task, attachment);
            throw t;
        } catch (Error t) {
            failed(notifier, t, task, attachment);
            throw t;
        } catch (Throwable t) {
            failed(notifier, t, task, attachment);
            throw Messages.msg.unknownThrowable(t);
        } finally {
            if (ok) finished(notifier, task, attachment);
        }
    }

    /**
     * Run a task, invoking the given notifier with the given attachment.
     *
     * @param task the task
     * @param notifier the notifier
     * @param attachment the attachment
     * @param  the task type
     * @param  the attachment type
     */
    public static  void run(R task, TaskNotifier notifier, A attachment) {
        run(task, directExecutor(), notifier, attachment);
    }

    /**
     * Get a notifying runnable wrapper for a task.  The notifier will be invoked when the task is run.
     *
     * @param task the task
     * @param notifier the notifier
     * @param attachment the attachment
     * @param  the task type
     * @param  the attachment type
     * @return the wrapping runnable
     */
    public static  Runnable notifyingRunnable(R task, TaskNotifier notifier, A attachment) {
        return new NotifyingRunnable(task, notifier, attachment);
    }

    /**
     * Get a notifying direct executor.  The notifier will be invoked when each task is run.
     *
     * @param delegate the executor which will actually run the task
     * @param notifier the notifier
     * @param attachment the attachment
     * @param  the attachment type
     * @return the direct executor
     */
    public static  DirectExecutor notifyingDirectExecutor(DirectExecutor delegate, TaskNotifier notifier, A attachment) {
        return new NotifyingDirectExecutor(delegate, notifier, attachment);
    }

    /**
     * Execute a task uninterruptibly.
     *
     * @param executor the executor to delegate to
     * @param task the task to execute
     * @throws RejectedExecutionException if the task was rejected by the executor
     */
    public static void executeUninterruptibly(Executor executor, Runnable task) throws RejectedExecutionException {
        boolean intr = Thread.interrupted();
        try {
            for (;;) {
                try {
                    executor.execute(task);
                    return;
                } catch (ExecutionInterruptedException e) {
                    intr |= Thread.interrupted();
                }
            }
        } finally {
            if (intr) {
                Thread.currentThread().interrupt();
            }
        }
    }

    /**
     * Get an executor which executes tasks uninterruptibly in the event of blocking.
     *
     * @param delegate the delegate executor
     * @return the uninterruptible executor
     */
    public static Executor uninterruptibleExecutor(final Executor delegate) {
        if (delegate instanceof UninterruptibleExecutor) {
            return delegate;
        } else {
            return new UninterruptibleExecutor(delegate);
        }
    }

    /**
     * Create a builder for a dependent task.
     *
     * @param executor the executor to use
     * @param task the task to run when all dependencies are met
     * @return the builder
     */
    public static DependencyTaskBuilder dependencyTaskBuilder(final Executor executor, final Runnable task) {
        return new DependencyTaskBuilder(executor, task);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy