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

jaxx.runtime.swing.application.ActionExecutor Maven / Gradle / Ivy

There is a newer version: 3.0-alpha-6
Show newest version
/*
 * #%L
 * JAXX :: Runtime
 * %%
 * Copyright (C) 2008 - 2014 Code Lutin, Tony Chemit
 * %%
 * 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 jaxx.runtime.swing.application;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuiton.util.ReflectUtil;

import javax.swing.SwingWorker;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

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

    /** Logger */
    private static final Log log =
            LogFactory.getLog(ActionExecutor.class);

    /** current tasks */
    protected final Set> tasks =
            new HashSet>();

    /** the listener of running action */
    protected final PropertyChangeListener workerListener;

    /**
     * Hook when a action is about to start.
     *
     * @param source the action worker containing the action to perform
     */
    public abstract void onActionStart(ActionWorker source);

    /**
     * Hook when a action has failed.
     *
     * @param source the action worker containing the action to perform
     */
    public abstract void onActionFail(ActionWorker source);

    /**
     * Hook when a action has been canceled.
     *
     * @param source the action worker containing the action to perform
     */
    public abstract void onActionCancel(ActionWorker source);

    /**
     * Hook when a action has end with no failure or cancel.
     *
     * @param source the action worker containing the action to perform
     */
    public abstract void onActionEnd(ActionWorker source);

    /**
     * Hook atfer action is consumed.
     *
     * @param source the action worker containing the action to perform
     */
    public abstract void onAfterAction(ActionWorker source);

    public ActionExecutor() {
        workerListener = new PropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if (log.isDebugEnabled()) {
                    log.debug("action " + evt.getSource() + " property " +
                              evt.getPropertyName() + " changed <" +
                              evt.getOldValue() + " - " + evt.getNewValue() +
                              '>');
                }

                if ("state".equals(evt.getPropertyName())) {
                    ActionWorker source = (ActionWorker) evt.getSource();
                    SwingWorker.StateValue state =
                            (SwingWorker.StateValue) evt.getNewValue();

                    if (state == SwingWorker.StateValue.STARTED) {
                        // starting new action

                        onActionStart(source);
                        return;
                    }

                    if (state == SwingWorker.StateValue.DONE) {
                        // on rend la main au thread pour qu'il attende une
                        // prochaine operation

                        ActionWorker.ActionStatus status = source.getStatus();
                        if (log.isDebugEnabled()) {
                            log.debug("Action [" + source.getActionLabel() +
                                      "] status = " + status);
                        }
                        try {
                            switch (status) {

                                case OK:
                                    onActionEnd(source);
                                    break;
                                case CANCEL:
                                    onActionCancel(source);
                                    break;
                                case FAIL:
                                    onActionFail(source);
                                    break;
                            }
                        } finally {
                            tasks.remove(source);
                            onAfterAction(source);
                        }
                    }
                }
            }
        };
    }

    /**
     * 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) {

        ActionWorker worker;
        if (action instanceof ActionWorker) {

            worker = (ActionWorker) action;
        } else {

            worker = new ActionWorker(actionLabel, action);
        }
        worker.addPropertyChangeListener(workerListener);
        tasks.add(worker);
        worker.execute();
        return worker;
    }

    /**
     * Ask the thread to stop.
     * 

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

* Note: The method does not return until all tasks are not * consumed. * * @throws InterruptedException if something wrong while waiting end of * executor */ public void terminatesAndWaits() throws InterruptedException { if (log.isDebugEnabled()) { log.debug("Executor " + this + " is terminating..."); } // ask executor to terminate for (ActionWorker task : tasks) { task.cancel(true); } if (log.isDebugEnabled()) { log.debug("Executor " + this + " is terminated at " + new Date()); } } public int getNbActions() { return getTasks().size(); } public Set> getTasks() { return tasks; } /** * Creates a runnable instance (via a Proxy) to a method given by his name * ({@code methodName}) to invoke on {@code methodcontainer} with given * {@code arguments}. *

* This is a great feature to create runnable code with a real context. * * @param methodContainer the container of the method to invoke * @param methodName the name of the method to invoke * @param arguments parameters to pass to method to invke. * @return the proxy instance */ public Runnable createRunnable(final Object methodContainer, String methodName, final Object... arguments) { // find method Class klass = methodContainer.getClass(); final Method targetMethod = ReflectUtil.getDeclaredMethod(klass, methodName, true, arguments ); targetMethod.setAccessible(true); Runnable result; // create runnable proxy result = (Runnable) Proxy.newProxyInstance( getClass().getClassLoader(), new Class[]{Runnable.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) { String methodName = method.getName(); if ("run".equals(methodName)) { try { if (log.isDebugEnabled()) { log.debug("will invoke run method"); } return targetMethod.invoke(methodContainer, arguments); } catch (IllegalAccessException e) { throw new RuntimeException( "could not invoke on container " + methodContainer, e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } if (methodName.equals("toString")) { return toString(); } if (methodName.equals("equals")) { return equals(args[0]); } if (methodName.equals("hashCode")) { return hashCode(); } return null; } } ); return result; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy