diff --git a/src/main/java/fr/moribus/imageonmap/ImageOnMap.java b/src/main/java/fr/moribus/imageonmap/ImageOnMap.java index b1e9307..32a4b2d 100644 --- a/src/main/java/fr/moribus/imageonmap/ImageOnMap.java +++ b/src/main/java/fr/moribus/imageonmap/ImageOnMap.java @@ -20,7 +20,9 @@ package fr.moribus.imageonmap; import fr.moribus.imageonmap.commands.Commands; import fr.moribus.imageonmap.image.ImageIOExecutor; +import fr.moribus.imageonmap.image.ImageRendererExecutor; import fr.moribus.imageonmap.image.MapInitEvent; +import fr.moribus.imageonmap.map.MapManager; import java.io.File; import org.bukkit.plugin.java.JavaPlugin; @@ -62,8 +64,11 @@ public final class ImageOnMap extends JavaPlugin } } + //Init all the things ! MetricsLite.startMetrics(); ImageIOExecutor.start(); + ImageRendererExecutor.start(); + MapManager.init(); Commands.init(this); getServer().getPluginManager().registerEvents(new MapInitEvent(), this); } @@ -72,6 +77,8 @@ public final class ImageOnMap extends JavaPlugin public void onDisable() { ImageIOExecutor.stop(); + ImageRendererExecutor.stop(); + MapManager.exit(); } } diff --git a/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java b/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java index dcd5929..403720a 100644 --- a/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java +++ b/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java @@ -22,6 +22,8 @@ import fr.moribus.imageonmap.commands.Command; import fr.moribus.imageonmap.commands.CommandException; import fr.moribus.imageonmap.commands.CommandInfo; import fr.moribus.imageonmap.commands.Commands; +import fr.moribus.imageonmap.image.ImageRendererExecutor; +import fr.moribus.imageonmap.worker.WorkerCallback; import java.net.MalformedURLException; import java.net.URL; import org.bukkit.entity.Player; @@ -36,7 +38,7 @@ public class NewCommand extends Command @Override protected void run() throws CommandException { - Player player = playerSender(); + final Player player = playerSender(); URL url; if(args.length < 1) throwInvalidArgument("You must give an URL to take the image from."); @@ -55,7 +57,21 @@ public class NewCommand extends Command } - info("Not implemented."); + info("Working ..."); + ImageRendererExecutor.Test(new WorkerCallback() + { + @Override + public void finished(Object... args) + { + player.sendMessage("Long task finished !"); + } + + @Override + public void errored(Throwable exception) + { + player.sendMessage("Whoops, an error occured !"); + } + }); } } diff --git a/src/main/java/fr/moribus/imageonmap/image/ImageRendererExecutor.java b/src/main/java/fr/moribus/imageonmap/image/ImageRendererExecutor.java new file mode 100644 index 0000000..f33e355 --- /dev/null +++ b/src/main/java/fr/moribus/imageonmap/image/ImageRendererExecutor.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2013 Moribus + * Copyright (C) 2015 ProkopyL + * + * 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 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 Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package fr.moribus.imageonmap.image; + +import fr.moribus.imageonmap.worker.Worker; +import fr.moribus.imageonmap.worker.WorkerCallback; +import fr.moribus.imageonmap.worker.WorkerRunnable; + +public class ImageRendererExecutor extends Worker +{ + static private ImageRendererExecutor instance; + + static public void start() + { + if(instance != null) stop(); + instance = new ImageRendererExecutor(); + instance.init(); + } + + static public void stop() + { + instance.exit(); + instance = null; + } + + private ImageRendererExecutor() + { + super("Image IO"); + } + + static public void Test(WorkerCallback callback) + { + instance.submitQuery(new WorkerRunnable() + { + @Override + public void run() throws Throwable + { + Thread.sleep(5000); + } + }, callback); + } + +} diff --git a/src/main/java/fr/moribus/imageonmap/worker/Worker.java b/src/main/java/fr/moribus/imageonmap/worker/Worker.java index d5b1f54..6dec9df 100644 --- a/src/main/java/fr/moribus/imageonmap/worker/Worker.java +++ b/src/main/java/fr/moribus/imageonmap/worker/Worker.java @@ -42,6 +42,7 @@ public abstract class Worker PluginLogger.LogWarning("Restarting " + name + " thread."); exit(); } + callbackManager.init(); thread = createThread(); thread.start(); } @@ -49,6 +50,7 @@ public abstract class Worker public void exit() { thread.interrupt(); + callbackManager.exit(); thread = null; } @@ -74,10 +76,11 @@ public abstract class Worker try { currentRunnable.run(); + callbackManager.callback(currentRunnable); } catch(Throwable ex) { - PluginLogger.LogError("Exception from thread " + name, ex); + callbackManager.callback(currentRunnable, ex); } } } @@ -91,6 +94,12 @@ public abstract class Worker } } + protected void submitQuery(WorkerRunnable runnable, WorkerCallback callback, Object... args) + { + callbackManager.setupCallback(runnable, callback, args); + submitQuery(runnable); + } + private Thread createThread() { diff --git a/src/main/java/fr/moribus/imageonmap/worker/WorkerCallbackManager.java b/src/main/java/fr/moribus/imageonmap/worker/WorkerCallbackManager.java index 845b1d9..c92e2ce 100644 --- a/src/main/java/fr/moribus/imageonmap/worker/WorkerCallbackManager.java +++ b/src/main/java/fr/moribus/imageonmap/worker/WorkerCallbackManager.java @@ -18,19 +18,23 @@ package fr.moribus.imageonmap.worker; +import fr.moribus.imageonmap.ImageOnMap; import java.util.ArrayDeque; import java.util.HashMap; import org.bukkit.Bukkit; +import org.bukkit.scheduler.BukkitTask; class WorkerCallbackManager implements Runnable { - static private final int WATCH_LOOP_DELAY = 5; + static private final int WATCH_LOOP_DELAY = 40; - private final HashMap callbacks; - private final ArrayDeque callbackQueue; + private final HashMap callbacks; + private final ArrayDeque callbackQueue; private final String name; + private BukkitTask selfTask; + public WorkerCallbackManager(String name) { callbacks = new HashMap<>(); @@ -40,16 +44,104 @@ class WorkerCallbackManager implements Runnable public void init() { - //Bukkit.getScheduler().runTaskTimer(null, this, 0, WATCH_LOOP_DELAY); + selfTask = Bukkit.getScheduler().runTaskTimer(ImageOnMap.getPlugin(), this, 0, WATCH_LOOP_DELAY); + } + + public void setupCallback(WorkerRunnable runnable, WorkerCallback callback, Object[] args) + { + synchronized(callbacks) + { + callbacks.put(runnable, new WorkerRunnableInfo(callback, args)); + } + } + + public void callback(WorkerRunnable runnable) + { + callback(runnable, null); + } + + public void callback(WorkerRunnable runnable, Throwable exception) + { + WorkerRunnableInfo runnableInfo; + synchronized(callbacks) + { + runnableInfo = callbacks.get(runnable); + } + if(runnableInfo == null) return; + runnableInfo.setRunnableException(exception); + + enqueueCallback(runnableInfo); } public void exit() { - + if(selfTask != null) selfTask.cancel(); + } + + private void enqueueCallback(WorkerRunnableInfo runnableInfo) + { + synchronized(callbackQueue) + { + callbackQueue.add(runnableInfo); + } } @Override public void run() { + WorkerRunnableInfo currentRunnableInfo; + synchronized(callbackQueue) + { + if(callbackQueue.isEmpty()) return; + currentRunnableInfo = callbackQueue.pop(); + } + + currentRunnableInfo.runCallback(); + } + + private class WorkerRunnableInfo + { + private final WorkerCallback callback; + private final Object[] args; + private Throwable runnableException; + + public WorkerRunnableInfo(WorkerCallback callback, Object[] args) + { + this.callback = callback; + this.args = args; + this.runnableException = null; + } + + public WorkerCallback getCallback() + { + return callback; + } + + public void runCallback() + { + if(runnableCrashed()) + { + callback.errored(runnableException); + } + else + { + callback.finished(args); + } + } + + public Throwable getRunnableException() + { + return runnableException; + } + + public void setRunnableException(Throwable runnableException) + { + this.runnableException = runnableException; + } + + public boolean runnableCrashed() + { + return this.runnableException != null; + } } }