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

org.apache.sshd.common.util.threads.ThreadUtils Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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.apache.sshd.common.util.threads;

import java.io.IOException;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.concurrent.Callable;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

import org.apache.sshd.common.util.ReflectionUtils;
import org.apache.sshd.common.util.io.functors.IOFunction;

/**
 * Utility class for thread pools.
 *
 * @author Apache MINA SSHD Project
 */
public final class ThreadUtils {

    /**
     * Marks framework-internal threads.
     */
    private static final ThreadLocal IS_INTERNAL_THREAD = new ThreadLocal<>();

    private ThreadUtils() {
        throw new UnsupportedOperationException("No instance");
    }

    /**
     * Runs a piece of code given as a {@link Callable} with a flag set indicating that the executing thread is an
     * Apache MINA sshd framework-internal thread.
     *
     * @param         return type
     * @param  code      code to run
     * @return           the result of {@code code}
     * @throws Exception propagated from {@code code.call()}
     * @see              #isInternalThread()
     */
    public static  V runAsInternal(Callable code) throws Exception {
        if (isInternalThread()) {
            return code.call();
        }
        try {
            IS_INTERNAL_THREAD.set(Boolean.TRUE);
            return code.call();
        } finally {
            IS_INTERNAL_THREAD.remove();
        }
    }

    /**
     * Runs an {@link IOFunction} with a flag set indicating that the executing thread is an Apache MINA sshd
     * framework-internal thread.
     *
     * @param           parameter type
     * @param           return type
     * @param  param       parameter for the function
     * @param  code        function to run
     * @return             the result of {@code code}
     * @throws IOException propagated from {@code code.apply()}
     * @see                #isInternalThread()
     */
    public static  V runAsInternal(T param, IOFunction code) throws IOException {
        if (isInternalThread()) {
            return code.apply(param);
        }
        try {
            IS_INTERNAL_THREAD.set(Boolean.TRUE);
            return code.apply(param);
        } finally {
            IS_INTERNAL_THREAD.remove();
        }
    }

    /**
     * Tells whether the calling thread is an Apache MINA sshd framework-internal thread.
     *
     * @return {@code true} if the thread is considered internal to the framework; {@code false} if not
     * @see    #runAsInternal(Callable)
     */
    public static boolean isInternalThread() {
        return Boolean.TRUE.equals(IS_INTERNAL_THREAD.get());
    }

    /**
     * Wraps an {@link CloseableExecutorService} in such a way as to "protect" it for calls to the
     * {@link CloseableExecutorService#shutdown()} or {@link CloseableExecutorService#shutdownNow()}. All other calls
     * are delegated as-is to the original service. Note: the exposed wrapped proxy will answer correctly the
     * {@link CloseableExecutorService#isShutdown()} query if indeed one of the {@code shutdown} methods was invoked.
     *
     * @param  executorService The original service - ignored if {@code null}
     * @param  shutdownOnExit  If {@code true} then it is OK to shutdown the executor so no wrapping takes place.
     * @return                 Either the original service or a wrapped one - depending on the value of the
     *                         shutdownOnExit parameter
     */
    public static CloseableExecutorService protectExecutorServiceShutdown(
            CloseableExecutorService executorService, boolean shutdownOnExit) {
        if (executorService == null || shutdownOnExit || executorService instanceof NoCloseExecutor) {
            return executorService;
        }
        return new NoCloseExecutor(executorService);
    }

    public static CloseableExecutorService noClose(CloseableExecutorService executorService) {
        return protectExecutorServiceShutdown(executorService, false);
    }

    public static ClassLoader resolveDefaultClassLoader(Object anchor) {
        return resolveDefaultClassLoader((anchor == null) ? null : anchor.getClass());
    }

    public static Iterable resolveDefaultClassLoaders(Object anchor) {
        return resolveDefaultClassLoaders((anchor == null) ? null : anchor.getClass());
    }

    public static Iterable resolveDefaultClassLoaders(Class anchor) {
        return () -> iterateDefaultClassLoaders(anchor);
    }

    public static Class resolveDefaultClass(Class anchor, String className) {
        return resolveDefaultClass(resolveDefaultClassLoaders(anchor), className);
    }

    public static Class resolveDefaultClass(Iterable cls, String className) {
        for (ClassLoader cl : cls) {
            try {
                return cl.loadClass(className);
            } catch (Throwable ignored) {
                // Ignore
            }
        }
        return null;
    }

    public static  T createDefaultInstance(
            Class anchor, Class targetType, String className)
            throws ReflectiveOperationException {
        return createDefaultInstance(resolveDefaultClassLoaders(anchor), targetType, className);
    }

    public static  T createDefaultInstance(
            ClassLoader cl, Class targetType, String className)
            throws ReflectiveOperationException {
        Class instanceType = cl.loadClass(className);
        return ReflectionUtils.newInstance(instanceType, targetType);
    }

    public static  T createDefaultInstance(
            Iterable cls, Class targetType, String className)
            throws ReflectiveOperationException {
        for (ClassLoader cl : cls) {
            try {
                return createDefaultInstance(cl, targetType, className);
            } catch (ClassNotFoundException e) {
                // Ignore
            }
        }
        throw new ClassNotFoundException(className);
    }

    /**
     * 

* Attempts to find the most suitable {@link ClassLoader} as follows: *

*
    *
  • *

    * Check the {@link Thread#getContextClassLoader()} value *

    *
  • * *
  • *

    * If no thread context class loader then check the anchor class (if given) for its class loader *

    *
  • * *
  • *

    * If still no loader available, then use {@link ClassLoader#getSystemClassLoader()} *

    *
  • *
* * @param anchor The anchor {@link Class} to use if no current thread context class loader - ignored if * {@code null} * * @return The resolved {@link ClassLoader} - Note: might still be {@code null} if went all the way * "down" to the system class loader and it was also {@code null}. */ public static ClassLoader resolveDefaultClassLoader(Class anchor) { Thread thread = Thread.currentThread(); ClassLoader cl = thread.getContextClassLoader(); if (cl != null) { return cl; } if (anchor != null) { cl = anchor.getClassLoader(); } if (cl == null) { // can happen for core Java classes cl = ClassLoader.getSystemClassLoader(); } return cl; } public static Iterator iterateDefaultClassLoaders(Class anchor) { Class effectiveAnchor = (anchor == null) ? ThreadUtils.class : anchor; return new Iterator() { @SuppressWarnings({ "unchecked", "checkstyle:Indentation" }) private final Supplier[] suppliers = new Supplier[] { () -> { Thread thread = Thread.currentThread(); return thread.getContextClassLoader(); }, effectiveAnchor::getClassLoader, ClassLoader::getSystemClassLoader }; private int index; @Override public boolean hasNext() { for (; index < suppliers.length; index++) { Supplier scl = suppliers[index]; ClassLoader cl = scl.get(); if (cl != null) { return true; } } return false; } @Override public ClassLoader next() { if (index >= suppliers.length) { throw new NoSuchElementException("All elements exhausted"); } Supplier scl = suppliers[index]; index++; return scl.get(); } }; } public static CloseableExecutorService newFixedThreadPoolIf( CloseableExecutorService executorService, String poolName, int nThreads) { return executorService == null ? newFixedThreadPool(poolName, nThreads) : executorService; } public static CloseableExecutorService newFixedThreadPool(String poolName, int nThreads) { return new SshThreadPoolExecutor( nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, // TODO make this configurable new LinkedBlockingQueue<>(), new SshdThreadFactory(poolName), new ThreadPoolExecutor.CallerRunsPolicy()); } public static CloseableExecutorService newCachedThreadPoolIf( CloseableExecutorService executorService, String poolName) { return executorService == null ? newCachedThreadPool(poolName) : executorService; } public static CloseableExecutorService newCachedThreadPool(String poolName) { return new SshThreadPoolExecutor( 0, Integer.MAX_VALUE, // TODO make this configurable 60L, TimeUnit.SECONDS, // TODO make this configurable new SynchronousQueue<>(), new SshdThreadFactory(poolName), new ThreadPoolExecutor.CallerRunsPolicy()); } public static ScheduledExecutorService newSingleThreadScheduledExecutor(String poolName) { return new ScheduledThreadPoolExecutor(1, new SshdThreadFactory(poolName)); } public static CloseableExecutorService newSingleThreadExecutor(String poolName) { return newFixedThreadPool(poolName, 1); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy