org.jcurl.core.ui.TaskExecutor.java Source code

Java tutorial

Introduction

Here is the source code for org.jcurl.core.ui.TaskExecutor.java

Source

/*
 * jcurl java curling software framework http://www.jcurl.org Copyright (C)
 * 2005-2009 M. Rohrmoser
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 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 Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307 USA
 */

package org.jcurl.core.ui;

import java.lang.reflect.ParameterizedType;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;

import javax.swing.SwingUtilities;

import org.apache.commons.logging.Log;
import org.jcurl.core.log.JCLoggerFactory;

/**
 * Dispatch {@link Task}s to the according {@link Executor}.
 * 
 * <ul>
 * <li>http://java.sun.com/javase/6/docs/api/javax/swing/SwingWorker.html</li>
 * <li>Fowler: http://martinfowler.com/eaaDev/EventCollaboration.html</li>
 * <li>EventBus https://eventbus.dev.java.net/
 * https://aptframework.dev.java.net/article/edtMessageBus.html</li>
 * <li><a href="https://beansbinding.dev.java.net/">JSR-295 Beans Binding</a></li>
 * <li><a href="https://appframework.dev.java.net/">JSR-296 Swing Application
 * Framework</a></li>
 * </ul>
 * 
 * @author <a href="mailto:m@jcurl.org">M. Rohrmoser </a>
 * @version $Id$
 */
public class TaskExecutor implements Executor {

    /** Execute in the current Thread */
    public static class Current implements Executor {
        public void execute(final Runnable command) {
            command.run();
        }
    }

    public static class ExecutorDelegate implements Executor {
        private final Executor base;

        public ExecutorDelegate(final Executor base) {
            this.base = base;
        }

        public void execute(final Runnable command) {
            base.execute(command);
        }
    }

    /**
     * Similar to {@link ForkableFlex} but early-bound to an {@link Executor}.
     * 
     * @param <T>
     *            see {@link TaskExecutor#execute(Runnable, Class)}
     * @author <a href="mailto:m@jcurl.org">M. Rohrmoser </a>
     * @version $Id$
     */
    public static abstract class ForkableFixed<T extends Executor> implements Task<T> {
        private final Executor ex;

        /**
         * Delegate to {@link ForkableFixed#ForkableFixed(Executor)} with
         * {@link TaskExecutor#getInstance()}.
         */
        public ForkableFixed() {
            this(TaskExecutor.getInstance());
        }

        /**
         * Enable dependency injaction for testing purposes.
         * 
         * @param ex
         */
        public ForkableFixed(final Executor ex) {
            this.ex = ex;
        }

        /** Delegate <code>this</code> to {@link Executor#execute(Runnable)} */
        public void fork() {
            ex.execute(this);
        }
    }

    /**
     * Similar to {@link ForkableFixed} but late-bound to an {@link Executor}.
     * 
     * @author <a href="mailto:m@jcurl.org">M. Rohrmoser </a>
     * @version $Id$
     */
    public static abstract class ForkableFlex implements Runnable {
        private final TaskExecutor ex;

        /**
         * Delegate to {@link ForkableFlex#ForkableFlex(TaskExecutor)} with
         * {@link TaskExecutor#getInstance()}.
         */
        public ForkableFlex() {
            this(TaskExecutor.getInstance());
        }

        /**
         * Enable dependency injaction for testing purposes.
         * 
         * @param ex
         */
        public ForkableFlex(final TaskExecutor ex) {
            this.ex = ex;
        }

        /**
         * Delegate <code>this</code> to
         * {@link TaskExecutor#execute(Runnable, Class)}
         */
        public void fork(final Class<? extends Executor> dst) {
            ex.execute(this, dst);
        }
    }

    /** Execute in a multi threaded pool executor. */
    public static class Parallel extends ExecutorDelegate {
        public Parallel() {
            super(Executors.newCachedThreadPool());
        }
    }

    /** Execute in a single threaded executor. */
    public static class Single extends ExecutorDelegate {
        public Single() {
            super(Executors.newSingleThreadExecutor());
        }
    }

    /**
     * TODO Execute in a single threaded executor but remove duplicates from the
     * queue.
     */
    public static class SmartQueue extends ExecutorDelegate {
        public SmartQueue() {
            super(Executors.newSingleThreadExecutor());
        }
    }

    /** Execute in the Swing/AWT Event Queue Thread */
    public static class SwingEDT implements Executor {
        public void execute(final Runnable command) {
            SwingUtilities.invokeLater(command);
        }
    }

    static interface Task<T extends Executor> extends Runnable {
    }

    private static final TaskExecutor instance = new TaskExecutor();

    private static final Log log = JCLoggerFactory.getLogger(TaskExecutor.class);

    /** Find the presence of a generic type parameter. */
    @SuppressWarnings("unchecked")
    static Class<Executor> findMessageTypeParam(final Class<? extends Task> clz) {
        if (Object.class.equals(clz.getGenericSuperclass())) {
            final ParameterizedType pt = (ParameterizedType) clz.getGenericInterfaces()[0];
            return (Class<Executor>) pt.getActualTypeArguments()[0];
        }
        final ParameterizedType pt = (ParameterizedType) clz.getGenericSuperclass();
        return (Class<Executor>) pt.getActualTypeArguments()[0];
    }

    static TaskExecutor getInstance() {
        return instance;
    }

    private final Map<Class<? extends Executor>, Executor> map = new WeakHashMap<Class<? extends Executor>, Executor>();

    private TaskExecutor() {
    }

    /**
     * Cast down to {@link Task} and delegate to
     * {@link #execute(org.jcurl.core.ui.TaskExecutor.Task)}.
     * 
     * @throws RejectedExecutionException
     *             if the downcast fails.
     */
    @SuppressWarnings("unchecked")
    public void execute(final Runnable command) {
        try {
            execute((Task<? extends Executor>) command);
        } catch (final ClassCastException e) {
            throw new RejectedExecutionException(e);
        }
    }

    /**
     * Delegate to the {@link Executor#execute(Runnable)} of the type parameter.
     * 
     * Keeps a {@link Map} class-&gt;instance.
     * 
     * @param msg
     * @param et
     *            executor to delegate to.
     * @throws RejectedExecutionException
     *             {@link Class#newInstance()} of the type parameter failed.
     */
    public void execute(final Runnable msg, final Class<? extends Executor> et) {
        log.debug(et);
        Executor ex;
        try {
            synchronized (et) {
                ex = map.get(et);
                if (ex == null)
                    map.put(et, ex = et.newInstance());
            }
        } catch (final InstantiationException e) {
            throw new RejectedExecutionException(e);
        } catch (final IllegalAccessException e) {
            throw new RejectedExecutionException(e);
        }
        ex.execute(msg);
    }

    /**
     * Delegate to the {@link #execute(Runnable, Class)}.
     * 
     * Uses {@link #findMessageTypeParam(Class)} to find the {@link Executor}
     * type parameter
     * 
     * @param msg
     */
    void execute(final Task<? extends Executor> msg) {
        execute(msg, findMessageTypeParam(msg.getClass()));
    }
}