Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/* --------------------------------------------------------------------
* Inugami
* --------------------------------------------------------------------
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package io.inugami.commons.threads;
import io.inugami.api.exceptions.Asserts;
import io.inugami.api.loggers.Loggers;
import io.inugami.api.models.tools.Chrono;
import io.inugami.api.monitoring.MonitoringInitializer;
import io.inugami.api.monitoring.RequestContext;
import io.inugami.api.monitoring.RequestInformation;
import io.inugami.api.spi.SpiLoader;
import lombok.Builder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiFunction;
/**
* ThreadsExecutor
*
* @author patrickguillerm
* @since 24 mars 2018
*/
@SuppressWarnings({"java:S3014", "java:S2142", "java:S1874"})
public class RunAndCloseService implements ThreadFactory {
// =========================================================================
// ATTRIBUTES
// =========================================================================
private static final Logger LOGGER = LoggerFactory.getLogger(RunAndCloseService.class);
private static final List monitoringInitializer = initMonitoringInitializers();
private final String threadsName;
private final List> tasks;
private final Map, Callable> tasksAndFutures;
private final long timeout;
private final BiFunction, T> onError;
private final ExecutorService executor;
private final CompletionService completion;
private final ThreadGroup threadGroup;
private final AtomicInteger threadIndex = new AtomicInteger();
private final List data = new ArrayList<>();
private final RequestInformation requestContext;
// =========================================================================
// CONSTRUCTORS
// =========================================================================
private static List initMonitoringInitializers() {
final List spiServices = SpiLoader.getInstance()
.loadSpiService(MonitoringInitializer.class);
return spiServices == null ? Collections.emptyList() : spiServices;
}
@SafeVarargs
public RunAndCloseService(final String threadsName, final long timeout, final int nbThreads,
final BiFunction, T> onError, final Callable... tasks) {
this(threadsName, timeout, nbThreads, Arrays.asList(tasks), onError);
}
@SafeVarargs
public RunAndCloseService(final String threadsName, final long timeout, final int nbThreads,
final Callable... tasks) {
this(threadsName, timeout, nbThreads, Arrays.asList(tasks), null);
}
public RunAndCloseService(final String threadsName, final long timeout, final int nbThreads,
final List> tasks) {
this(threadsName, timeout, nbThreads, tasks, null);
}
public RunAndCloseService(final String threadsName, final long timeout, final int nbThreads,
final List> tasks, final BiFunction, T> onError) {
this(threadsName, timeout, nbThreads, null, tasks, onError);
}
@Builder
public RunAndCloseService(final String threadsName,
final long timeout,
final int nbThreads,
final ExecutorService executor,
final List> tasks,
final BiFunction, T> onError) {
super();
Asserts.assertNotNull(tasks);
this.tasks = tasks;
ExecutorService currentExecutor = executor;
if (executor == null) {
int howManyThreads = tasks.size() < nbThreads ? tasks.size() : nbThreads;
if (howManyThreads <= 0) {
howManyThreads = 1;
}
currentExecutor = Executors.newFixedThreadPool(howManyThreads, this);
}
this.executor = currentExecutor;
this.threadsName = threadsName;
this.timeout = timeout;
this.onError = onError;
tasksAndFutures = new HashMap<>();
threadGroup = Thread.currentThread().getThreadGroup();
completion = new ExecutorCompletionService<>(currentExecutor);
this.requestContext = RequestContext.getInstance();
}
// =========================================================================
// METHODS
// =========================================================================
public List run() {
final List> futures = sumitTask();
int tasksLeft = futures.size();
long timeLeft = timeout;
final Chrono chrono = Chrono.startChrono();
while ((tasksLeft > 0) && (chrono.snapshot().getDuration() < timeout)) {
timeLeft = computeTimeLeft(timeLeft, chrono);
Future itemFuture = null;
T taskData = null;
try {
itemFuture = completion.poll(timeLeft, TimeUnit.MILLISECONDS);
if (itemFuture != null) {
taskData = itemFuture.get();
tasksLeft = tasksLeft - 1;
}
} catch (final ExecutionException | InterruptedException error) {
tasksLeft = tasksLeft - 1;
}
if (taskData != null) {
data.add(taskData);
}
}
executor.shutdown();
data.addAll(handlerTimeoutTask());
return data;
}
private long computeTimeLeft(final long timeLeft, final Chrono chrono) {
final long result = timeLeft - chrono.snapshot().getDuration();
return result < 0 ? 0 : result;
}
// =========================================================================
// PRIVATE
// =========================================================================
private List> sumitTask() {
final List> result = new ArrayList<>();
for (final Callable task : tasks) {
final Future future = completion.submit(new CallableTask<>(task, this));
result.add(future);
tasksAndFutures.put(future, task);
}
return result;
}
private class CallableTask implements Callable {
private final Callable task;
private final RunAndCloseService runAndCloseService;
public CallableTask(final Callable task, final RunAndCloseService runAndCloseService) {
this.task = task;
this.runAndCloseService = runAndCloseService;
}
@Override
public U call() throws Exception {
U result = null;
try {
result = task.call();
} catch (final Exception e) {
LOGGER.error(e.getMessage(), e);
result = runAndCloseService.processHandlerError(e, task);
}
return result;
}
}
// =========================================================================
// new Thread
// =========================================================================
@Override
public Thread newThread(final Runnable runnable) {
final String name = String.join(".", threadsName, String.valueOf(threadIndex.getAndIncrement()));
final Thread result = new MonitoredThread(threadGroup, runnable, name, 10, requestContext,
monitoringInitializer);
result.setDaemon(false);
return result;
}
// =========================================================================
// ERRORS
// =========================================================================
private List handlerTimeoutTask() {
final List result = new ArrayList<>();
for (final Map.Entry, Callable> entry : tasksAndFutures.entrySet()) {
if (!entry.getKey().isDone()) {
final Callable task = entry.getValue();
final T taskData = processHandlerError(null, task);
if (taskData != null) {
result.add(taskData);
}
}
}
return result;
}
private synchronized T processHandlerError(final Exception error, final Callable task) {
T result = null;
if (onError == null) {
result = handlerError(error, task);
} else {
result = onError.apply(error, task);
}
return result;
}
private T handlerError(final Exception error, final Callable task) {
T result = null;
if (task instanceof CallableWithErrorResult) {
if (error == null) {
result = ((CallableWithErrorResult) task).getTimeoutResult();
} else {
result = ((CallableWithErrorResult) task).getErrorResult(error);
}
}
return result;
}
public void forceShutdown() {
if (!executor.isShutdown()) {
if (!executor.isTerminated()) {
try {
executor.awaitTermination(0, TimeUnit.MILLISECONDS);
} catch (final InterruptedException e) {
Loggers.DEBUG.error(e.getMessage(), e);
}
}
executor.shutdown();
}
}
}