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

org.nuiton.jaxx.runtime.application.action.ActionExecutor Maven / Gradle / Ivy

There is a newer version: 3.1.5
Show newest version
/*
 * #%L
 * JAXX :: Runtime
 * %%
 * Copyright (C) 2008 - 2024 Code Lutin, Ultreia.io
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * 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 Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */
package org.nuiton.jaxx.runtime.application.action;

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.nuiton.jaxx.runtime.application.ApplicationBoot;
import org.nuiton.jaxx.runtime.application.ApplicationContext;
import org.nuiton.jaxx.runtime.application.action.event.ActionExecutorEvent;
import org.nuiton.jaxx.runtime.application.action.event.ActionExecutorListener;
import org.nuiton.jaxx.runtime.application.action.event.DefaultActionExecutorListener;

import javax.swing.SwingWorker;
import javax.swing.event.EventListenerList;
import java.beans.PropertyChangeListener;
import java.io.Closeable;
import java.util.Date;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Executor of {@link ActionWorker}.
 *
 * @author Tony Chemit - [email protected]
 * @since 2.1
 */
public class ActionExecutor implements Closeable {

    private static final Logger log = LogManager.getLogger(ActionExecutor.class);
    /**
     * Current running actions.
     */
    private final Set> tasks = new HashSet<>();
    /**
     * Listener to attach on running actions to dispatch his internal state via {@link ActionExecutorListener}.
     */
    private final PropertyChangeListener workerListener;
    /**
     * To store listeners.
     */
    private final EventListenerList eventListenerList;
    /**
     * Application boot.
     */
    private final ApplicationBoot boot;
    /**
     * Executor service.
     */
    private ThreadPoolExecutor executorService;

    public ActionExecutor(ApplicationBoot boot, ApplicationContext context) {
        this.boot = boot;
        this.eventListenerList = new EventListenerList();
        this.workerListener = evt -> onActionWorkerChanged((ActionWorker) evt.getSource(), evt.getPropertyName(), evt.getOldValue(), evt.getNewValue());
        addActionExecutorListener(new DefaultActionExecutorListener(context));
    }

    public void addActionExecutorListener(ActionExecutorListener listener) {
        eventListenerList.add(ActionExecutorListener.class, Objects.requireNonNull(listener));
    }

    public void removeActionExecutorListener(ActionExecutorListener listener) {
        eventListenerList.remove(ActionExecutorListener.class, Objects.requireNonNull(listener));
    }

    public ActionExecutorListener[] getActionExecutorListeners() {
        return eventListenerList.getListeners(ActionExecutorListener.class);
    }

    /**
     * Add an new action to perform.
     *
     * @param actionLabel the name of the action to perform
     * @param action      the action to perform
     * @return the worker that will launch the action
     */
    public ActionWorker addAction(String actionLabel, Runnable action) {
//        boot.checkNotClosed("executor");
        ActionWorker worker;
        if (action instanceof ActionWorker) {
            worker = (ActionWorker) action;
        } else {
            worker = new ActionWorker(actionLabel, action);
        }
        worker.addPropertyChangeListener(workerListener);
        tasks.add(worker);
        log.debug("Launch worker [" + actionLabel + "] now...");
        try {
            getWorkersExecutorService().execute(worker);
        } catch (RejectedExecutionException e) {
            log.error(String.format("Worker was rejected: %s for reason: %s", worker, e.getMessage()), e);
        }
        log.debug("Launch worker [" + actionLabel + "] is on...");
        return worker;
    }

    /**
     * Ask the stop any running actions.
     * 

* It will finish all incoming files (but will not accept more tasks). *

* Note: The method does not return until all tasks are not consumed. */ @Override public void close() { log.info("Executor " + this + " is terminating..."); // for (ActionWorker task : tasks) { // log.info(String.format("cancel task: %s", task.getActionLabel())); // task.cancel(true); // } if (executorService != null) { try { executorService.awaitTermination(1000, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { log.error("Can't terminate executor service, will shutdown it."); } executorService.shutdownNow(); executorService = null; } for (ActionExecutorListener listener : getActionExecutorListeners()) { removeActionExecutorListener(listener); } log.info("Executor " + this + " is terminated at " + new Date()); } public int getNbActions() { return getTasks().size(); } public Set> getTasks() { return tasks; } private void onActionWorkerChanged(ActionWorker source, String propertyName, Object oldValue, Object newValue) { log.debug(String.format("action %s property %s changed <%s - %s>", source, propertyName, oldValue, newValue)); switch (propertyName) { case "state": SwingWorker.StateValue state = (SwingWorker.StateValue) Objects.requireNonNull(newValue); if (SwingWorker.StateValue.STARTED == state) { // starting new action fireActionStart(this, source); return; } if (SwingWorker.StateValue.DONE == state) { // action done, let's dispatch to correct callback ActionWorker.ActionStatus status = source.getStatus(); log.debug(String.format("Action [%s] status = %s", source.getActionLabel(), status)); try { switch (status) { case OK: // normal end fireActionEnd(this, source); break; case CANCEL: // cancel end fireActionCancel(this, source); break; case FAIL: // error end fireActionFail(this, source); break; } } finally { source.removePropertyChangeListener(workerListener); tasks.remove(source); fireAfterAction(this, source); } } break; } } /** * On surcharge celui offer par SwingWorker car le corepool est à 1 et cela * ne permet pas d'exécuter plusieurs actions en même temps... * necessary. * * @return ExecutorService for the {@link ActionWorker} */ public ThreadPoolExecutor getWorkersExecutorService() { // boot.checkNotClosed("Executor service"); if (executorService == null) { executorService = new ThreadPoolExecutor(5, 10, 10L, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), boot.getThreadFactory()); } return executorService; } private void fireActionStart(ActionExecutor executor, ActionWorker source) { ActionExecutorEvent event = null; for (ActionExecutorListener listener : getActionExecutorListeners()) { if (event == null) { event = new ActionExecutorEvent(source, executor); } listener.onActionStart(event); } } private void fireActionFail(ActionExecutor executor, ActionWorker source) { ActionExecutorEvent event = null; for (ActionExecutorListener listener : getActionExecutorListeners()) { if (event == null) { event = new ActionExecutorEvent(source, executor); } listener.onActionFail(event); } } private void fireActionCancel(ActionExecutor executor, ActionWorker source) { ActionExecutorEvent event = null; for (ActionExecutorListener listener : getActionExecutorListeners()) { if (event == null) { event = new ActionExecutorEvent(source, executor); } listener.onActionCancel(event); } } private void fireActionEnd(ActionExecutor executor, ActionWorker source) { ActionExecutorEvent event = null; for (ActionExecutorListener listener : getActionExecutorListeners()) { if (event == null) { event = new ActionExecutorEvent(source, executor); } listener.onActionEnd(event); } } private void fireAfterAction(ActionExecutor executor, ActionWorker source) { ActionExecutorEvent event = null; for (ActionExecutorListener listener : getActionExecutorListeners()) { if (event == null) { event = new ActionExecutorEvent(source, executor); } listener.onAfterAction(event); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy