org.apache.sshd.common.util.threads.ThreadUtils 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).
/*
* 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 super T, V> 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 extends ClassLoader> 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 extends T> targetType, String className)
throws ReflectiveOperationException {
return createDefaultInstance(resolveDefaultClassLoaders(anchor), targetType, className);
}
public static T createDefaultInstance(
ClassLoader cl, Class extends T> targetType, String className)
throws ReflectiveOperationException {
Class> instanceType = cl.loadClass(className);
return ReflectionUtils.newInstance(instanceType, targetType);
}
public static T createDefaultInstance(
Iterable extends ClassLoader> cls, Class extends T> 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 extends ClassLoader>[] 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 extends ClassLoader> 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 extends ClassLoader> 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);
}
}