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

io.inugami.commons.threads.ThreadsExecutorService Maven / Gradle / Ivy

There is a newer version: 3.3.5
Show newest version
/* --------------------------------------------------------------------
 *  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.exceptions.TechnicalException;
import io.inugami.api.listeners.TaskFinishListener;
import io.inugami.api.listeners.TaskStartListener;
import io.inugami.api.loggers.Loggers;
import io.inugami.api.models.tools.Chrono;
import io.inugami.api.providers.concurrent.LifecycleBootstrap;

import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.*;
import java.util.function.BiConsumer;

/**
 * ThreadsExecutorService
 *
 * @author patrick_guillerm
 * @since 13 janv. 2017
 */
@SuppressWarnings({"java:S1186", "java:S2142", "java:S2139"})
public class ThreadsExecutorService implements LifecycleBootstrap {

    // =========================================================================
    // ATTRIBUTES
    // =========================================================================

    private final long timeout;

    private final String name;

    private final ExecutorService executor;

    private final ExecutorService executorCompletable;

    // =========================================================================
    // CONSTRUCTORS
    // =========================================================================
    public ThreadsExecutorService(final String name, final int maxThreads) {
        this(name, maxThreads, false, null);
    }

    public ThreadsExecutorService(final String name, final int maxThreads, final boolean deamon) {
        this(name, maxThreads, deamon, null);
    }

    public ThreadsExecutorService(final String name, final int maxThreads, final boolean deamon, final Long timeout) {
        this.name = name == null ? "ThreadsExecutor" : name;
        final MonitoredThreadFactory threadFactory = new MonitoredThreadFactory(this.name, deamon);
        executor = Executors.newFixedThreadPool(maxThreads, threadFactory);
        executorCompletable = Executors.newFixedThreadPool(maxThreads, threadFactory);

        this.timeout = timeout == null ? 30000L : timeout.longValue();

    }

    // =========================================================================
    // RUN
    // =========================================================================
    public  List> run(final List> tasks) {
        return run(tasks, null, null);
    }

    public  List> run(final List> tasks, final BiConsumer> onDone) {
        return run(tasks, onDone, null);
    }

    public  List> run(final List> tasks, final BiConsumer> onDone,
                                              final BiConsumer> onError) {
        final List> result = new ArrayList<>();

        if ((tasks != null) && !tasks.isEmpty()) {
            for (int i = 0; i < tasks.size(); i++) {
                final CompletableFuture future = buildFuture(tasks.get(i), onDone, onError);
                result.add(future);
            }
        }

        return result;
    }

    // =========================================================================
    // RUN AND GRAB
    // =========================================================================
    public  List runAndGrab(final List> tasks) throws TechnicalException {
        return runAndGrab(tasks, null, null, timeout);
    }

    public  List runAndGrab(final List> tasks,
                                  final BiConsumer> onDone,
                                  final BiConsumer> onError) throws TechnicalException {
        return runAndGrab(tasks, onDone, onError, timeout);
    }

    public  List runAndGrab(final List> tasks, final long timeout) throws TechnicalException {
        return runAndGrab(tasks, null, null, timeout);
    }

    public  List runAndGrab(final List> tasks, final BiConsumer> onDone,
                                  final long timeout) throws TechnicalException {
        return runAndGrab(tasks, onDone, null, timeout);
    }


    public  List runAndGrab(final List> tasks, final BiConsumer> onDone,
                                  final BiConsumer> onError,
                                  final long timeout) throws TechnicalException {
        final List result = new ArrayList<>();

        final List> futures = run(tasks, (data, task) -> {
            result.add(data);
            onDone.accept(data, task);
        }, onError);
        waitting(futures, timeout);

        return result;
    }

    // =========================================================================
    // WAIT
    // =========================================================================
    public  void waitting(final List> futures, final long timeout) throws TechnicalException {
        if ((futures != null) && !futures.isEmpty()) {

            final Chrono chrono = Chrono.startChrono();


            for (final CompletableFuture future : futures) {
                chrono.snapshot();
                long localTimeout = timeout - chrono.getDuration();

                if (localTimeout > 0) {
                    try {
                        future.get(localTimeout, TimeUnit.MILLISECONDS);
                    } catch (final InterruptedException | ExecutionException | TimeoutException e) {
                        Loggers.PLUGINS.error(e.getMessage());
                        throw new TechnicalException(e.getMessage(), e);
                    }
                }
            }

        }
    }

    // =========================================================================
    // BUILDER
    // =========================================================================
    public  CompletableFuture buildFuture(final Callable taskToProcess) {
        return buildFuture(taskToProcess, null, null);
    }

    public  CompletableFuture buildFuture(final Callable taskToProcess,
                                                final BiConsumer> onDone) {
        return buildFuture(taskToProcess, onDone, null);
    }

    public  CompletableFuture buildFuture(final Callable taskToProcess,
                                                final BiConsumer> onDone,
                                                final BiConsumer> onError) {
        // @formatter:off
        final BiConsumer> functionOnDone = onDone != null ? onDone : (data, task) -> {
        };
        final BiConsumer> functionOnError = onError != null ? onError : (error, task) -> {
        };
        // @formatter:on
        final Future future = run(taskToProcess);

        final CompletableFuture result = CompletableFuture.supplyAsync(() -> {
            T futureResult = null;
            try {
                futureResult = future.get(timeout, TimeUnit.MILLISECONDS);

            } catch (final InterruptedException | ExecutionException | TimeoutException e) {
                if ((e instanceof ExecutionException) && (e.getCause() instanceof NoSuchElementException)) {
                    futureResult = null;
                } else {
                    Loggers.DEBUG.error(e.getMessage(), e);
                    functionOnError.accept(e, taskToProcess);
                    future.cancel(true);
                }
            }

            return futureResult;
        }, executorCompletable);

        result.thenAcceptAsync(data -> functionOnDone.accept(data, taskToProcess));

        return result;
    }

    private  Future run(final Callable taskToProcess) {
        return executor.submit(taskToProcess);
    }

    public  Future submit(final String name, final Callable task) {
        return submit(name, task, null, null);
    }

    public  Future submit(final String name, final Callable task, final TaskFinishListener listener) {
        return submit(name, task, listener, null);
    }

    public  Future submit(final String name, final Callable task, final TaskFinishListener finishListner,
                                final TaskStartListener startListner) {
        return executor.submit(new ThreadsExecutorTask(name, task, startListner, finishListner));
    }

    // =========================================================================
    // LifecycleBootstrap
    // =========================================================================
    @Override
    public void start() {
    }

    @Override
    public void shutdown() {
        shutdownExecutor(executor);
        shutdownExecutor(executorCompletable);
    }

    private void shutdownExecutor(final ExecutorService localExecutor) {
        localExecutor.shutdown();

        try {
            localExecutor.awaitTermination(500, TimeUnit.MILLISECONDS);
        } catch (final InterruptedException e) {
            Loggers.DEBUG.debug(e.getMessage(), e);
            localExecutor.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }

    // =========================================================================
    // THREAD
    // =========================================================================
    private class ThreadsExecutorTask implements Callable {
        private final String name;

        private final Callable task;

        private final TaskStartListener startListner;

        private final TaskFinishListener finishListner;

        public ThreadsExecutorTask(final String name, final Callable task, final TaskStartListener startListner,
                                   final TaskFinishListener finishListner) {
            Asserts.assertNotNull("name mustn't be null!", name);
            Asserts.assertNotNull("task mustn't be null!", task);
            this.name = name;
            this.task = task;
            this.startListner = startListner;
            this.finishListner = finishListner;

        }

        @Override
        public T call() throws Exception {
            final long startTime = System.currentTimeMillis();

            if (startListner != null) {
                startListner.onStart(startTime, name);
            }

            final Exception error  = null;
            T               result = null;
            try {
                result = task.call();
            } catch (final Exception e) {
                Loggers.DEBUG.error(e.getMessage(), e);
                Loggers.XLLOG.error(e.getMessage());
                throw e;
            } finally {
                if (finishListner != null) {
                    final long endTime = System.currentTimeMillis();
                    final long delais  = startTime - endTime;
                    finishListner.onFinish(endTime, delais, name, result, error);
                }
            }

            return result;
        }

    }

    public ExecutorService getExecutor() {
        return executor;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy