ferrybig icon

MainThreadPlanner.java - a class designed for Bukkit progra.

ferrybig | PRO | 07/27/14 06:31:41 PM UTC | 0 ⭐ | 722 👁️ | Never ⏰ | []
Java |

4.73 KB

|

None

|

0 👍

/

0 👎

package sander;
 
import java.util.ArrayList;
import static java.util.Collections.addAll;
import java.util.List;
import static org.bukkit.Bukkit.getScheduler;
import org.bukkit.plugin.Plugin;
 
public class MainThreadPlanner<T> {
 
    private AccumulativeRunnable<T> doProcess;
    private final AccumulativeRunnable<Runnable> doSubmit;
    protected final Plugin plugin;
    private final Processor<T> processor;
 
    public MainThreadPlanner(Plugin plugin,Processor<T> processor) {
        this.doSubmit = new DoSubmitAccumulativeRunnable(plugin);
        this.plugin = plugin;
        this.processor = processor;
    }
 
    private void process(List<T> chunks) {
        this.processor.process(chunks);
    }
 
    /**
     * Sends data chunks to the {@link #process} method. This method is to be
     * used from inside the {@code doInBackground} method to deliver
     * intermediate results for processing on the <i>Bukkit Main Server
     * Thread</i> inside the {@code process} method.
     *
     * <p>
     * Because the {@code process} method is invoked asynchronously on the
     * <i>Bukkit Main Server Thread</i>
     * multiple invocations to the {@code publish} method might occur before the
     * {@code process} method is executed. For performance purposes all these
     * invocations are coalesced into one invocation with concatenated
     * arguments.
     *
     * <p>
     * For example:
     *
     * <pre>
     * publish(&quot;1&quot;);
     * publish(&quot;2&quot;, &quot;3&quot;);
     * publish(&quot;4&quot;, &quot;5&quot;, &quot;6&quot;);
     * </pre>
     *
     * might result in:
     *
     * <pre>
     * process(&quot;1&quot;, &quot;2&quot;, &quot;3&quot;, &quot;4&quot;, &quot;5&quot;, &quot;6&quot;)
     * </pre>
     *
     *
     * @param chunks intermediate results to process
     *
     * @see #process
     *
     */
    public final void publish(T... chunks) {
        synchronized (this) {
            if (this.doProcess == null) {
                this.doProcess = new AccumulativeRunnable<T>() {
                    @Override
                    public void run(List<T> args) {
                        MainThreadPlanner.this.process(args);
                    }
 
                    @Override
                    protected void submit() {
                        MainThreadPlanner.this.doSubmit.add(this);
                    }
                };
            }
        }
        this.doProcess.add(chunks);
    }
 
    private static abstract class AccumulativeRunnable<T extends Object> implements Runnable {
 
        private List<T> arguments = null;
 
        protected abstract void run(List<T> paramList);
 
        @Override
        public final void run() {
            this.run(this.flush());
        }
 
        public final synchronized void add(T... toAdd) {
            boolean mustSubmit = false;
            if (this.arguments == null) {
                mustSubmit = true;
                this.arguments = new ArrayList<>();
            }
            addAll(this.arguments, toAdd);
            if (mustSubmit) {
                this.submit();
            }
        }
 
        abstract protected void submit();
 
        private synchronized List<T> flush() {
            List<T> localList = this.arguments;
            this.arguments = null;
            return localList;
        }
    }
 
    public interface Processor<T> {
 
        public void process(List<T> process);
    }
 
    private class DoSubmitAccumulativeRunnable extends AccumulativeRunnable<Runnable> implements Runnable {
 
        /**
         * Time in ticks between 2 invokings of the schedular
         */
        private final static int DELAY = 1;
        /**
         * The plugin, used to schedule tasks
         */
        private final Plugin plugin;
 
        public DoSubmitAccumulativeRunnable(Plugin plugin) {
            this.plugin = plugin;
        }
 
        @Override
        protected void run(List<Runnable> args) {
            for (Runnable runnable : args) {
                runnable.run();
            }
        }
 
        @Override
        protected void submit() {
            if (this.plugin.isEnabled()) {
                getScheduler().scheduleSyncDelayedTask(this.plugin, this, DELAY);
            } else {
                // What do do, scheduling an task would throw an IllegalArgumentException, and enablking this plugin for a little time may cause bugs inside the plugin?
                // Mayby use reflection to access the enabled field of JavaPlugin, but this wont work whit plugins that dont exend that class
                throw new IllegalStateException("Plugin not enabled, unable to schadule task");
            }
        }
    }
}

Comments