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

com.enterprisemath.utils.engine.ExecutorServiceEngine Maven / Gradle / Ivy

Go to download

Collection of utility classes for large scale projects focusing on robust and testable code.

There is a newer version: 4.1.1
Show newest version
package com.enterprisemath.utils.engine;

import com.enterprisemath.utils.DatesProvider;
import com.enterprisemath.utils.DomainUtils;
import com.enterprisemath.utils.UniqueCodeGenerator;
import com.enterprisemath.utils.ValidationUtils;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.exception.ExceptionUtils;

/**
 * Implementation of engine which uses executor service.
 *
 * @author radek.hecl
 */
public class ExecutorServiceEngine implements Engine {

    /**
     * Builder object.
     */
    public static class Builder {

        /**
         * Executor.
         */
        private ExecutorService executor;

        /**
         * Provider for services.
         */
        private TaskServiceProvider serviceProvider;

        /**
         * Listener for task run.
         */
        private TaskRunListener listener;

        /**
         * Generator for unique code.
         */
        private UniqueCodeGenerator uniqueCodeGenerator;

        /**
         * Provider for dates.
         */
        private DatesProvider datesProvider;

        /**
         * Sets executor.
         *
         * @param executor executor
         * @return this instance
         */
        public Builder setExecutor(ExecutorService executor) {
            this.executor = executor;
            return this;
        }

        /**
         * Sets provider for services.
         *
         * @param serviceProvider provider for services
         * @return this instance
         */
        public Builder setServiceProvider(TaskServiceProvider serviceProvider) {
            this.serviceProvider = serviceProvider;
            return this;
        }

        /**
         * Sets listener.
         *
         * @param listener listener
         * @return this instance
         */
        public Builder setListener(TaskRunListener listener) {
            this.listener = listener;
            return this;
        }

        /**
         * Set generator for unique codes.
         *
         * @param uniqueCodeGenerator generator for unique codes
         * @return this instance
         */
        public Builder setUniqueCodeGenerator(UniqueCodeGenerator uniqueCodeGenerator) {
            this.uniqueCodeGenerator = uniqueCodeGenerator;
            return this;
        }

        /**
         * Sets provider for dates.
         *
         * @param datesProvider provider for dates
         * @return this instance
         */
        public Builder setDatesProvider(DatesProvider datesProvider) {
            this.datesProvider = datesProvider;
            return this;
        }

        /**
         * Builds the result object.
         *
         * @return created object
         */
        public ExecutorServiceEngine build() {
            return new ExecutorServiceEngine(this);
        }
    }

    /**
     * Executor.
     */
    private ExecutorService executor;

    /**
     * Provider for services.
     */
    private TaskServiceProvider serviceProvider;

    /**
     * Listener for task run.
     */
    private TaskRunListener listener;

    /**
     * Generator for unique code.
     */
    private UniqueCodeGenerator uniqueCodeGenerator;

    /**
     * Provider for dates.
     */
    private DatesProvider datesProvider;

    /**
     * Task handlers.
     */
    private List handlers = new ArrayList();

    /**
     * Object for synchronization.
     */
    private final Object lock = new Object();

    /**
     * Creates new instance.
     *
     * @param builder builder object
     */
    public ExecutorServiceEngine(Builder builder) {
        executor = builder.executor;
        serviceProvider = builder.serviceProvider;
        listener = builder.listener;
        uniqueCodeGenerator = builder.uniqueCodeGenerator;
        datesProvider = builder.datesProvider;
        guardInvariants();
    }

    /**
     * Guards this object to be consistent. Throws exception if this is not the case.
     */
    private void guardInvariants() {
        ValidationUtils.guardNotNull(executor, "executor cannot be null");
        ValidationUtils.guardNotNull(serviceProvider, "serviceProvider cannot be null");
        ValidationUtils.guardNotNull(listener, "listener cannot be null");
        ValidationUtils.guardNotNull(uniqueCodeGenerator, "uniqueCodeGenerator cannot be null");
        ValidationUtils.guardNotNull(datesProvider, "datesProvider cannot be null");
    }

    @Override
    public EngineStatus getStatus() {
        synchronized (lock) {
            cleanHandlers();
            EngineStatus.Builder res = new EngineStatus.Builder();
            for (TaskHandler hdl : handlers) {
                EngineTaskStatus ets = new EngineTaskStatus.Builder().
                        setCode(hdl.getCode()).
                        setTaskClass(hdl.task.getClass().getName()).
                        setProgress(hdl.task.getProgress()).
                        setStartTimestamp(hdl.startTimestamp).
                        build();
                res.addTaskStatus(ets);
            }
            return res.build();
        }
    }

    @Override
    public TaskManager getTaskManager(String code) {
        synchronized (lock) {
            cleanHandlers();
            for (TaskHandler hdl : handlers) {
                if (hdl.getCode().equals(code)) {
                    return hdl;
                }
            }
            return null;
        }
    }

    @Override
    public TaskManager run(TaskRunOrder order) {
        synchronized (lock) {
            TaskHandler handler = new TaskHandler(this, order);
            Future> f = executor.submit(handler);
            handler.future = f;
            cleanHandlers();
            handlers.add(handler);
            return handler;
        }
    }

    /**
     * Cleans handlers from all tasks which are done.
     * !!! This method is not thread safe. Has to be invoked in the thread safe context.
     */
    private void cleanHandlers() {
        List hdls = new ArrayList();
        for (TaskHandler th : handlers) {
            if (!th.isDone()) {
                hdls.add(th);
            }
        }
        handlers = hdls;
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }

    /**
     * Handler for tasks.
     */
    private static class TaskHandler implements TaskManager, Callable> {

        /**
         * Enumerates possible states.
         */
        private static enum State {

            /**
             * Task is running.
             */
            RUNNING,
            /**
             * Task is completed by return.
             */
            COMLPETED,
            /**
             * There was an exception during task.
             */
            EXCEPTION,
            /**
             * Task was stopped by command.
             */
            STOPPED

        }

        /**
         * Parent object.
         */
        private ExecutorServiceEngine parent;

        /**
         * Parameters.
         */
        private Map parameters;

        /**
         * Identification code.
         */
        private String code;

        /**
         * Timestamp when task started.
         */
        private Date startTimestamp;

        /**
         * Task to be invoked.
         */
        private Task task;

        /**
         * Future.
         */
        private Future> future = null;

        /**
         * State.
         */
        private State state = State.RUNNING;

        /**
         * Exception details.
         */
        private Map exceptionDetails = null;

        /**
         * Result.
         */
        private Map result = null;

        /**
         * Object for synchronization.
         */
        private final Object lock = new Object();

        /**
         * Creates new instance.
         *
         * @param parent parent object
         * @param order order for run
         * @param parameters parameters
         */
        public TaskHandler(ExecutorServiceEngine parent, TaskRunOrder order) {
            this.parent = parent;
            this.parameters = DomainUtils.softCopyUnmodifiableMap(order.getParameters());
            ValidationUtils.guardNotNull(parent, "parent cannot be null");
            ValidationUtils.guardNotEmptyNullMap(parameters, "parameters cannot have empty key or null value");

            // initialize
            code = parent.uniqueCodeGenerator.generateUniqueCode("TASK");
            startTimestamp = parent.datesProvider.now();
            task = order.createTaskInstance();
        }

        @Override
        public String getCode() {
            return code;
        }

        @Override
        public boolean isDone() {
            synchronized (lock) {
                return !state.equals(State.RUNNING);
            }
        }

        @Override
        public Map getResult() {
            synchronized (lock) {
                if (state.equals(State.COMLPETED)) {
                    return DomainUtils.softCopyMap(result);
                }
                else {
                    return null;
                }
            }
        }

        @Override
        public Map getExceptionDetails() {
            synchronized (lock) {
                if (state.equals(State.EXCEPTION)) {
                    return DomainUtils.softCopyMap(exceptionDetails);
                }
                else {
                    return null;
                }
            }
        }

        @Override
        public void stop() {
            synchronized (lock) {
                if (state.equals(State.RUNNING)) {
                    state = State.STOPPED;
                    future.cancel(true);
                    parent.listener.runFinishedByStop(new TaskRunStopReport.Builder().
                            setCode(code).
                            setTaskClass(task.getClass().getName()).
                            setParameters(parameters).
                            setStartTimestamp(startTimestamp).
                            setEndTimestamp(parent.datesProvider.now()).
                            build());
                }
            }
        }

        @Override
        public void waitTillDone() {
            try {
                future.get();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } catch (ExecutionException e) {
                // nothing to do here, because task is already finished
            } catch (CancellationException e) {
                // nothing to do here, because task is already finished
            }
        }

        @Override
        public Map call() throws Exception {
            try {
                Map res = task.run(parent.serviceProvider, parameters);
                synchronized (lock) {
                    if (state.equals(State.RUNNING)) {
                        result = DomainUtils.softCopyMap(res);
                        state = State.COMLPETED;
                        parent.listener.runFinishedBySuccess(new TaskRunSuccessReport.Builder().
                                setCode(code).
                                setTaskClass(task.getClass().getName()).
                                setParameters(parameters).
                                setResult(result).
                                setStartTimestamp(startTimestamp).
                                setEndTimestamp(parent.datesProvider.now()).
                                build());
                    }
                }
            } catch (Throwable t) {
                synchronized (lock) {
                    if (state.equals(State.RUNNING)) {
                        exceptionDetails = new HashMap();
                        exceptionDetails.put("class", t.getClass().getName());
                        exceptionDetails.put("message", t.getMessage());
                        exceptionDetails.put("stackTrace", ExceptionUtils.getStackTrace(t));
                        state = State.EXCEPTION;
                        parent.listener.runFinishedByExceptin(new TaskRunExceptionReport.Builder().
                                setCode(code).
                                setTaskClass(task.getClass().getName()).
                                setParameters(parameters).
                                setExceptionDetails(exceptionDetails).
                                setStartTimestamp(startTimestamp).
                                setEndTimestamp(parent.datesProvider.now()).
                                build());
                    }
                }
            }
            return null;
        }

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy