Package ru.decipher.extraction.impl

Source Code of ru.decipher.extraction.impl.GeneralProcessor$ActiveTaskCountHandler

package ru.decipher.extraction.impl;

import org.apache.log4j.Logger;
import ru.decipher.exception.ProcessorTaskSubmissionException;
import ru.decipher.extraction.*;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
* Invokes tasks according to priority.
* <p/>
* Those <code>PayloadRequest</code>, which have higher value returned by <code>getPriority()</code>
* will be executed first
* <p/>
* <code>allowedDuplicates</code> shows how many duplicate requests are allowed to
* submit. (0) - means all requests are unique, (-1) - means don't care about duplicates,
* (>= 1) - means amount of allowed duplicates per request
* <p/>
* User: Alexander Paderin (apocarteres@gmail.com)
* Date: 10/20/13
* Time: 9:49 PM
*/
public class GeneralProcessor<T extends PayloadRequest> implements Processor<T> {
    private final ThreadPoolExecutor service;
    private final Object shutdownLock;
    private final Object duplicatesLock;
    private final AtomicInteger activeTasks;
    private final Map<T, Integer> duplicates;
    private final int allowedDuplicates;
    private final String description;
    private static final Logger log = Logger.getLogger(GeneralProcessor.class);

    public GeneralProcessor(int workers) {
        this(workers, "payload-processor");
    }

    public GeneralProcessor(int workers, String description) {
        this(workers, -1, description);
    }

    public GeneralProcessor(int workers, int allowedDuplicates, String description) {
        this.allowedDuplicates = allowedDuplicates;
        this.duplicatesLock = new Object();
        this.duplicates = new HashMap<>();
        this.description = description;
        this.service = new PayloadExecutor(workers, workers, 10, TimeUnit.MINUTES, new PriorityBlockingQueue<Runnable>());
        this.shutdownLock = new Object();
        this.activeTasks = new AtomicInteger(0);
    }

    @Override
    public Future<T> submit(PayloadTask<T> task) throws Exception {
        final DuplicateRequestHandler dupRequestHandler = new DuplicateRequestHandler();
        dupRequestHandler.prepareTask(task);
        task.registerHandler(dupRequestHandler);
        final ActiveTaskCountHandler taskCountHandler = new ActiveTaskCountHandler();
        task.registerHandler(taskCountHandler);
        taskCountHandler.inc();
        return service.submit(task);
    }

    @Override
    public long getTaskCount() {
        return activeTasks.get();
    }

    @Override
    public void shutdown() {
        log.debug("shutdown requested. waiting for queued tasks");
        synchronized (shutdownLock) {
            while (getTaskCount() > 0) {
                try {
                    shutdownLock.wait(60000);
                } catch (InterruptedException ignored) {
                }
            }
        }
        service.shutdown();
        log.info("shutdown completed");
    }

    class ActiveTaskCountHandler implements CallbackHandler<T> {

        private void inc() {
            activeTasks.incrementAndGet();
        }

        @Override
        public void onProcessorResponse(T request) {
            if (activeTasks.decrementAndGet() == 0) {
                synchronized (shutdownLock) {
                    shutdownLock.notifyAll();
                }
            }
        }

        @Override
        public <U extends Provider<? extends T>> void beforeExecution(T request, U provider) {

        }

    }

    class DuplicateRequestHandler implements CallbackHandler<T> {
        private void prepareTask(PayloadTask<T> task) {
            if (allowedDuplicates >= 0) {
                synchronized (duplicatesLock) {
                    final T request = task.getRequest();
                    Integer actual = duplicates.get(request);
                    if (actual == null) {
                        actual = 0;
                    } else {
                        actual++;
                    }
                    if (actual > allowedDuplicates) {
                        throw new ProcessorTaskSubmissionException(task + " can't be submitted. it exceeds duplicate request limit");
                    }
                    duplicates.put(request, actual);
                }
            }
        }

        @Override
        public void onProcessorResponse(T request) throws Exception {
            if (allowedDuplicates >= 0) {
                synchronized (duplicatesLock) {
                    Integer actual = duplicates.get(request);
                    if (actual != null) {
                        actual--;
                        if (actual < 0) {
                            duplicates.remove(request);
                        } else {
                            duplicates.put(request, actual);
                        }
                    }
                }
            }
        }

        @Override
        public <U extends Provider<? extends T>> void beforeExecution(T request, U provider) {

        }
    }

    class PayloadExecutor extends ThreadPoolExecutor {

        public PayloadExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
                               BlockingQueue<Runnable> workQueue) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
                    new ThreadFactory() {
                        @Override
                        public Thread newThread(Runnable r) {
                            final Thread thread = new Thread(r);
                            thread.setName(description + "-thread");
                            return thread;
                        }
                    }
            );
        }

        @SuppressWarnings("unchecked")
        @Override
        protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
            if (callable instanceof GeneralTask) {
                return new PayloadFuture<>(callable, ((GeneralTask) callable).getRequest().getPriority());
            }
            throw new IllegalStateException("only GeneralTask or derivatives allowed to submit");
        }
    }

    static class PayloadFuture<T> extends FutureTask<T> implements Comparable<PayloadFuture<T>> {
        private final Comparable<Object> priority;

        public PayloadFuture(Callable<T> callable, Comparable<Object> priority) {
            super(callable);
            this.priority = priority;
        }


        @Override
        public int compareTo(PayloadFuture<T> o) {
            return o.priority.compareTo(this.priority);
        }
    }
}





TOP

Related Classes of ru.decipher.extraction.impl.GeneralProcessor$ActiveTaskCountHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.