och.service.AsyncService.java Source code

Java tutorial

Introduction

Here is the source code for och.service.AsyncService.java

Source

/*
 * Copyright 2015 Evgeny Dolganov (evgenij.dolganov@gmail.com).
 *
 * 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 och.service;

import static och.util.ExceptionUtil.*;
import static och.util.Util.*;
import static och.util.concurrent.AsyncListener.*;
import static och.util.concurrent.ExecutorsUtil.*;

import java.lang.Thread.UncaughtExceptionHandler;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import och.api.exception.ExpectedException;
import och.util.concurrent.AsyncListener;
import och.util.model.CallableVoid;

import org.apache.commons.logging.Log;

public class AsyncService implements UncaughtExceptionHandler {

    private Log log = getLog(getClass());
    private ArrayList<AsyncListener> listeners = new ArrayList<>();
    private ArrayList<AsyncListener> scheduleListeners = new ArrayList<>();

    private ExecutorService workThreads;
    private ScheduledExecutorService scheduledService;

    public AsyncService() {
        this(10, 2);
    }

    public AsyncService(int asyncThreads, int scheduleThreads) {
        workThreads = newFixedThreadPool("AsyncService", asyncThreads, this);
        scheduledService = newScheduledThreadPool("AsyncService-scheduled", scheduleThreads, this);
    }

    public void addListener(AsyncListener l) {
        listeners.add(l);
    }

    public void addScheduleListener(AsyncListener l) {
        scheduleListeners.add(l);
    }

    public <T> Future<T> invoke(final Callable<T> task) {
        Future<T> future = workThreads.submit(new Callable<T>() {
            @Override
            public T call() throws Exception {
                try {

                    return task.call();

                } catch (Throwable t) {
                    ExpectedException.logError(log, t, "can't invoke async");
                    throw getExceptionOrThrowError(t);
                }
            }
        });
        fireAsyncEvent(listeners, future);
        return future;
    }

    /**
     * Good for simple cases
     * <pre>
     * task --- delay --- task
     * </pre>
     */
    public void scheduleWithFixedDelay(String commandName, Runnable command, long initialDelayMs, long delayMs) {

        logScheduleWithFixedDelay(commandName, delayMs);

        ScheduledFuture<?> future = scheduledService.scheduleWithFixedDelay(command, initialDelayMs, delayMs,
                TimeUnit.MILLISECONDS);
        fireScheduleEvent(future);
    }

    /**
     * Good for simple cases
     * <pre>
     * task --- delay --- task
     * </pre>
     */
    public void tryScheduleWithFixedDelay(String commandName, CallableVoid command, long initialDelayMs,
            long delayMs) {

        logScheduleWithFixedDelay(commandName, delayMs);

        ScheduledFuture<?> future = scheduledService.scheduleWithFixedDelay(() -> {
            try {
                command.call();
            } catch (Throwable t) {
                log.error("can't scheduleWithFixedDelay", t);
            }
        }, initialDelayMs, delayMs, TimeUnit.MILLISECONDS);
        fireScheduleEvent(future);
    }

    private void logScheduleWithFixedDelay(String commandName, long delayMs) {
        log.info("scheduleWithFixedDelay: '" + commandName + "' with delayMs=" + delayMs);
        if (delayMs < 60_000L)
            log.warn("very small delay " + delayMs + "ms for '" + commandName + "'");
    }

    /**
     * Good for time periods:
     * <pre>
     * period --- period --- period --- period
     * taaaaaaaaaaask                   taaaaaaaaaaask
     * </pre>
     */
    public void scheduleAtFixedRate(String commandName, Runnable command, long initialDelayMs, long periodMs) {

        logScheduleAtFixedRate(commandName, periodMs);

        ScheduledFuture<?> future = scheduledService.scheduleAtFixedRate(command, initialDelayMs, periodMs,
                TimeUnit.MILLISECONDS);
        fireScheduleEvent(future);
    }

    /**
     * Good for time periods:
     * <pre>
     * period --- period --- period --- period
     * taaaaaaaaaaask                   taaaaaaaaaaask
     * </pre>
     */
    public void tryScheduleAtFixedRate(String commandName, CallableVoid command, long initialDelayMs,
            long periodMs) {

        logScheduleAtFixedRate(commandName, periodMs);

        ScheduledFuture<?> future = scheduledService.scheduleAtFixedRate(() -> {
            try {
                command.call();
            } catch (Throwable t) {
                log.error("can't scheduleAtFixedRate", t);
            }
        }, initialDelayMs, periodMs, TimeUnit.MILLISECONDS);
        fireScheduleEvent(future);
    }

    private void logScheduleAtFixedRate(String commandName, long periodMs) {
        log.info("scheduleAtFixedRate: '" + commandName + "' with periodMs=" + periodMs);
        if (periodMs < 60_000L)
            log.warn("very small period " + periodMs + "ms for '" + commandName + "'");
    }

    private void fireScheduleEvent(Future<?> future) {
        for (AsyncListener l : scheduleListeners) {
            try {
                l.onFutureEvent(future);
            } catch (Throwable t) {
                log.error("schedule listener error", t);
            }
        }
    }

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        log.error("can't invoke async", e);
    }

}