From 91e34601ecfcfd47528b90f5abfa999583a66c41 Mon Sep 17 00:00:00 2001 From: sk89q Date: Sat, 16 Aug 2014 13:42:14 -0700 Subject: [PATCH] Add supervisor/task library in. --- pom.xml | 14 -- .../worldguard/bukkit/WorldGuardPlugin.java | 8 +- .../bukkit/commands/AsyncCommandHelper.java | 2 +- .../bukkit/commands/WorldGuardCommands.java | 5 +- .../managers/index/ChunkHashTable.java | 2 +- .../util/concurrent/EvenMoreExecutors.java | 54 ++++++ .../worldguard/util/task/AbstractTask.java | 74 +++++++ .../util/task/FutureForwardingTask.java | 121 ++++++++++++ .../util/task/SimpleSupervisor.java | 62 ++++++ .../worldguard/util/task/Supervisor.java | 44 +++++ .../com/sk89q/worldguard/util/task/Task.java | 97 ++++++++++ .../util/task/TaskStateComparator.java | 43 ++++ .../util/task/progress/Progress.java | 183 ++++++++++++++++++ .../util/task/progress/ProgressIterator.java | 100 ++++++++++ .../task/progress/ProgressObservable.java | 34 ++++ 15 files changed, 820 insertions(+), 23 deletions(-) create mode 100644 src/main/java/com/sk89q/worldguard/util/concurrent/EvenMoreExecutors.java create mode 100644 src/main/java/com/sk89q/worldguard/util/task/AbstractTask.java create mode 100644 src/main/java/com/sk89q/worldguard/util/task/FutureForwardingTask.java create mode 100644 src/main/java/com/sk89q/worldguard/util/task/SimpleSupervisor.java create mode 100644 src/main/java/com/sk89q/worldguard/util/task/Supervisor.java create mode 100644 src/main/java/com/sk89q/worldguard/util/task/Task.java create mode 100644 src/main/java/com/sk89q/worldguard/util/task/TaskStateComparator.java create mode 100644 src/main/java/com/sk89q/worldguard/util/task/progress/Progress.java create mode 100644 src/main/java/com/sk89q/worldguard/util/task/progress/ProgressIterator.java create mode 100644 src/main/java/com/sk89q/worldguard/util/task/progress/ProgressObservable.java diff --git a/pom.xml b/pom.xml index c42e9773..f935799b 100644 --- a/pom.xml +++ b/pom.xml @@ -199,15 +199,6 @@ true - - com.sk89q - odeum - 0.2.0-SNAPSHOT - compile - jar - true - - junit junit @@ -400,7 +391,6 @@ com.jolbox:bonecp org.flywaydb:flyway-core com.sk89q:squirrelid - com.sk89q:odeum @@ -416,10 +406,6 @@ com.sk89q.squirrelid com.sk89q.worldguard.util.profile - - com.sk89q.odeum - com.sk89q.worldguard.internal.odeum - diff --git a/src/main/java/com/sk89q/worldguard/bukkit/WorldGuardPlugin.java b/src/main/java/com/sk89q/worldguard/bukkit/WorldGuardPlugin.java index 5b0ba8ea..c2b60d85 100644 --- a/src/main/java/com/sk89q/worldguard/bukkit/WorldGuardPlugin.java +++ b/src/main/java/com/sk89q/worldguard/bukkit/WorldGuardPlugin.java @@ -30,10 +30,10 @@ import com.sk89q.minecraft.util.commands.MissingNestedCommandException; import com.sk89q.minecraft.util.commands.SimpleInjector; import com.sk89q.minecraft.util.commands.WrappedCommandException; -import com.sk89q.odeum.concurrent.EvenMoreExecutors; -import com.sk89q.odeum.task.SimpleSupervisor; -import com.sk89q.odeum.task.Supervisor; -import com.sk89q.odeum.task.Task; +import com.sk89q.worldguard.util.concurrent.EvenMoreExecutors; +import com.sk89q.worldguard.util.task.SimpleSupervisor; +import com.sk89q.worldguard.util.task.Supervisor; +import com.sk89q.worldguard.util.task.Task; import com.sk89q.squirrelid.cache.HashMapCache; import com.sk89q.squirrelid.cache.ProfileCache; import com.sk89q.squirrelid.cache.SQLiteCache; diff --git a/src/main/java/com/sk89q/worldguard/bukkit/commands/AsyncCommandHelper.java b/src/main/java/com/sk89q/worldguard/bukkit/commands/AsyncCommandHelper.java index a12862f3..dabc9fde 100644 --- a/src/main/java/com/sk89q/worldguard/bukkit/commands/AsyncCommandHelper.java +++ b/src/main/java/com/sk89q/worldguard/bukkit/commands/AsyncCommandHelper.java @@ -21,7 +21,7 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; -import com.sk89q.odeum.task.FutureForwardingTask; +import com.sk89q.worldguard.util.task.FutureForwardingTask; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import org.bukkit.World; import org.bukkit.command.CommandSender; diff --git a/src/main/java/com/sk89q/worldguard/bukkit/commands/WorldGuardCommands.java b/src/main/java/com/sk89q/worldguard/bukkit/commands/WorldGuardCommands.java index 9812e0eb..44325133 100644 --- a/src/main/java/com/sk89q/worldguard/bukkit/commands/WorldGuardCommands.java +++ b/src/main/java/com/sk89q/worldguard/bukkit/commands/WorldGuardCommands.java @@ -23,14 +23,13 @@ import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.minecraft.util.commands.CommandPermissions; -import com.sk89q.odeum.task.Task; -import com.sk89q.odeum.task.TaskStateComparator; +import com.sk89q.worldguard.util.task.Task; +import com.sk89q.worldguard.util.task.TaskStateComparator; import com.sk89q.worldguard.bukkit.util.LoggerToChatHandler; import com.sk89q.worldguard.bukkit.util.ReportWriter; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import com.sk89q.worldguard.util.PastebinPoster; import com.sk89q.worldguard.util.PastebinPoster.PasteCallback; -import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; diff --git a/src/main/java/com/sk89q/worldguard/protection/managers/index/ChunkHashTable.java b/src/main/java/com/sk89q/worldguard/protection/managers/index/ChunkHashTable.java index 7fcb15b2..a6718291 100644 --- a/src/main/java/com/sk89q/worldguard/protection/managers/index/ChunkHashTable.java +++ b/src/main/java/com/sk89q/worldguard/protection/managers/index/ChunkHashTable.java @@ -23,7 +23,7 @@ import com.google.common.base.Supplier; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; -import com.sk89q.odeum.concurrent.EvenMoreExecutors; +import com.sk89q.worldguard.util.concurrent.EvenMoreExecutors; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector2D; import com.sk89q.worldguard.protection.managers.RegionDifference; diff --git a/src/main/java/com/sk89q/worldguard/util/concurrent/EvenMoreExecutors.java b/src/main/java/com/sk89q/worldguard/util/concurrent/EvenMoreExecutors.java new file mode 100644 index 00000000..6b29fdd7 --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/util/concurrent/EvenMoreExecutors.java @@ -0,0 +1,54 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.util.concurrent; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingDeque; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * Provides additional executors. + */ +public final class EvenMoreExecutors { + + private EvenMoreExecutors() { + } + + /** + * Creates a thread pool that creates new threads as needed up to + * a maximum number of threads, but will reuse previously constructed + * threads when they are available. + * + * @param minThreads the minimum number of threads to have at a given time + * @param maxThreads the maximum number of threads to have at a given time + * @param queueSize the size of the queue before new submissions are rejected + * @return the newly created thread pool + */ + public static ExecutorService newBoundedCachedThreadPool(int minThreads, int maxThreads, int queueSize) { + ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( + minThreads, maxThreads, + 60L, TimeUnit.SECONDS, + new LinkedBlockingDeque(queueSize)); + threadPoolExecutor.allowCoreThreadTimeOut(true); + return threadPoolExecutor; + } + +} diff --git a/src/main/java/com/sk89q/worldguard/util/task/AbstractTask.java b/src/main/java/com/sk89q/worldguard/util/task/AbstractTask.java new file mode 100644 index 00000000..6e86edd3 --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/util/task/AbstractTask.java @@ -0,0 +1,74 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.util.task; + +import com.google.common.util.concurrent.AbstractFuture; + +import javax.annotation.Nullable; +import java.util.Date; +import java.util.UUID; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An abstract task that stores a name and owner. + * + * @param the type returned + */ +public abstract class AbstractTask extends AbstractFuture implements Task { + + private final UUID uniqueId = UUID.randomUUID(); + private final String name; + private final Object owner; + private final Date creationDate = new Date(); + + /** + * Create a new instance. + * + * @param name the name + * @param owner the owner + */ + protected AbstractTask(String name, @Nullable Object owner) { + checkNotNull(name); + this.name = name; + this.owner = owner; + } + + @Override + public UUID getUniqueId() { + return uniqueId; + } + + @Override + public String getName() { + return name; + } + + @Nullable + @Override + public Object getOwner() { + return owner; + } + + @Override + public Date getCreationDate() { + return creationDate; + } +} diff --git a/src/main/java/com/sk89q/worldguard/util/task/FutureForwardingTask.java b/src/main/java/com/sk89q/worldguard/util/task/FutureForwardingTask.java new file mode 100644 index 00000000..5cd66049 --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/util/task/FutureForwardingTask.java @@ -0,0 +1,121 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.util.task; + +import com.google.common.util.concurrent.ListenableFuture; +import com.sk89q.worldguard.util.task.progress.Progress; + +import javax.annotation.Nullable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A task that wraps a {@code ListenableFuture}. + * + *

{@link State#SCHEDULED} is never returned because it is not possible + * to test whether the future has "started," so {@link State#RUNNING} is + * returned in its place.

+ * + *

Use {@link #create(ListenableFuture, String, Object)} to create a new + * instance.

+ * + * @param the type returned + */ +public class FutureForwardingTask extends AbstractTask { + + private final ListenableFuture future; + + private FutureForwardingTask(ListenableFuture future, String name, @Nullable Object owner) { + super(name, owner); + checkNotNull(future); + this.future = future; + } + + @Override + public void addListener(Runnable listener, Executor executor) { + future.addListener(listener, executor); + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + return future.cancel(mayInterruptIfRunning); + } + + @Override + public boolean isCancelled() { + return future.isCancelled(); + } + + @Override + public boolean isDone() { + return future.isDone(); + } + + @Override + public V get() throws InterruptedException, ExecutionException { + return future.get(); + } + + @Override + public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + return future.get(timeout, unit); + } + + @Override + public State getState() { + if (isCancelled()) { + return State.CANCELLED; + } else if (isDone()) { + try { + get(); + return State.SUCCEEDED; + } catch (InterruptedException e) { + return State.CANCELLED; + } catch (ExecutionException e) { + return State.FAILED; + } + } else { + return State.RUNNING; + } + } + + @Override + public Progress getProgress() { + return Progress.indeterminate(); + } + + /** + * Create a new instance. + * + * @param future the future + * @param name the name of the task + * @param owner the owner of the task, or {@code null} + * @param the type returned by the future + * @return a new instance + */ + public static com.sk89q.worldguard.util.task.FutureForwardingTask create(ListenableFuture future, String name, @Nullable Object owner) { + return new com.sk89q.worldguard.util.task.FutureForwardingTask(future, name, owner); + } + +} diff --git a/src/main/java/com/sk89q/worldguard/util/task/SimpleSupervisor.java b/src/main/java/com/sk89q/worldguard/util/task/SimpleSupervisor.java new file mode 100644 index 00000000..0757077c --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/util/task/SimpleSupervisor.java @@ -0,0 +1,62 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.util.task; + +import com.google.common.util.concurrent.MoreExecutors; + +import java.util.ArrayList; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An implementation of a {@code Supervisor}. + */ +public class SimpleSupervisor implements Supervisor { + + private final List> monitored = new ArrayList>(); + private final Object lock = new Object(); + + @Override + public List> getTasks() { + synchronized (lock) { + return new ArrayList>(monitored); + } + } + + @Override + public void monitor(final Task task) { + checkNotNull(task); + + synchronized (lock) { + monitored.add(task); + } + + task.addListener(new Runnable() { + @Override + public void run() { + synchronized (lock) { + monitored.remove(task); + } + } + }, MoreExecutors.sameThreadExecutor()); + } + +} diff --git a/src/main/java/com/sk89q/worldguard/util/task/Supervisor.java b/src/main/java/com/sk89q/worldguard/util/task/Supervisor.java new file mode 100644 index 00000000..b357ba37 --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/util/task/Supervisor.java @@ -0,0 +1,44 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.util.task; + +import java.util.List; + +/** + * Manages running tasks and informs users of their progress, but does not + * execute the task. + */ +public interface Supervisor { + + /** + * Get a list of running or queued tasks. + * + * @return a list of tasks + */ + List> getTasks(); + + /** + * Monitor the given task. + * + * @param task the task + */ + void monitor(Task task); + +} diff --git a/src/main/java/com/sk89q/worldguard/util/task/Task.java b/src/main/java/com/sk89q/worldguard/util/task/Task.java new file mode 100644 index 00000000..b9d03b01 --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/util/task/Task.java @@ -0,0 +1,97 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.util.task; + +import com.google.common.util.concurrent.ListenableFuture; +import com.sk89q.worldguard.util.task.progress.ProgressObservable; + +import javax.annotation.Nullable; +import java.util.Date; +import java.util.UUID; + +/** + * A task is a job that can be scheduled, run, or cancelled. Tasks can report + * on their own status. Tasks have owners. + */ +public interface Task extends ListenableFuture, ProgressObservable { + + /** + * Get the unique ID of this task. + * + * @return this task's unique ID + */ + UUID getUniqueId(); + + /** + * Get the name of the task so it can be printed to the user. + * + * @return the name of the task + */ + String getName(); + + /** + * Get the owner of the task. + * + * @return an owner object, if one is known or valid, otherwise {@code null} + */ + @Nullable + Object getOwner(); + + /** + * Get the state of the task. + * + * @return the state of the task + */ + State getState(); + + /** + * Get the time at which the task was created. + * + * @return a date + */ + Date getCreationDate(); + + /** + * Represents the state of a task. + */ + public enum State { + /** + * The task has been scheduled to run but is not running yet. + */ + SCHEDULED, + /** + * The task has been cancelled and may be stopped or will stop. + */ + CANCELLED, + /** + * The task is currently running. + */ + RUNNING, + /** + * The task has failed. + */ + FAILED, + /** + * The task has succeeded. + */ + SUCCEEDED + } + +} diff --git a/src/main/java/com/sk89q/worldguard/util/task/TaskStateComparator.java b/src/main/java/com/sk89q/worldguard/util/task/TaskStateComparator.java new file mode 100644 index 00000000..1804cc35 --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/util/task/TaskStateComparator.java @@ -0,0 +1,43 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.util.task; + +import java.util.Comparator; + +/** + * Compares task states according to the order of the {@link com.sk89q.worldguard.util.task.Task.State} + * enumeration. + */ +public class TaskStateComparator implements Comparator> { + + @Override + public int compare(com.sk89q.worldguard.util.task.Task o1, Task o2) { + int ordinal1 = o1.getState().ordinal(); + int ordinal2 = o2.getState().ordinal(); + if (ordinal1 < ordinal2) { + return -1; + } else if (ordinal1 > ordinal2) { + return 1; + } else { + return 0; + } + } + +} diff --git a/src/main/java/com/sk89q/worldguard/util/task/progress/Progress.java b/src/main/java/com/sk89q/worldguard/util/task/progress/Progress.java new file mode 100644 index 00000000..31bbe010 --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/util/task/progress/Progress.java @@ -0,0 +1,183 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.util.task.progress; + +import java.util.Arrays; +import java.util.Collection; + +/** + * A progress object describes the progress of an operation, specifying + * either a percentage of completion or a status of indeterminacy. + * + *

Progress objects are immutable.

+ * + *

To create a new instance, use one of the static constructors + * on this class.

+ */ +public abstract class Progress { + + /** + * Create a new instance. + */ + private Progress() { + } + + /** + * Return whether the current progress is indeterminate. + * + * @return true if indeterminate + */ + public abstract boolean isIndeterminate(); + + /** + * Get the progress percentage. + * + *

If {@link #isIndeterminate()} returns {@code true}, the behavior + * of this method is undefined.

+ * + * @return a number in the range [0, 1] + */ + public abstract double getProgress(); + + /** + * Get a static progress object that is indeterminate. + * + * @return a progress object + */ + public static com.sk89q.worldguard.util.task.progress.Progress indeterminate() { + return INDETERMINATE; + } + + /** + * Get a static progress object that is complete. + * + * @return a progress object + */ + public static com.sk89q.worldguard.util.task.progress.Progress completed() { + return COMPLETED; + } + + /** + * Create a new progress object with the given percentage. + * + * @param value the percentage, which will be clamped to [0, 1] + * @return a progress object + */ + public static com.sk89q.worldguard.util.task.progress.Progress of(double value) { + if (value < 0) { + value = 0; + } else if (value > 1) { + value = 1; + } + + final double finalValue = value; + return new com.sk89q.worldguard.util.task.progress.Progress() { + @Override + public boolean isIndeterminate() { + return false; + } + + @Override + public double getProgress() { + return finalValue; + } + }; + } + + /** + * Create a new progress object with progress split equally between the + * given progress objects. + * + * @param objects an array of progress objects + * @return a new progress value + */ + public static com.sk89q.worldguard.util.task.progress.Progress split(com.sk89q.worldguard.util.task.progress.Progress... objects) { + return split(Arrays.asList(objects)); + } + + /** + * Create a new progress object with progress split equally between the + * given progress objects. + * + * @param progress a collection of progress objects + * @return a new progress value + */ + public static com.sk89q.worldguard.util.task.progress.Progress split(Collection progress) { + int count = 0; + double total = 0; + + for (com.sk89q.worldguard.util.task.progress.Progress p : progress) { + if (p.isIndeterminate()) { + return indeterminate(); + } + total += p.getProgress(); + } + + return of(total / count); + } + + /** + * Create a new progress object with progress split equally between the + * given {@link com.sk89q.worldguard.util.task.progress.ProgressObservable}s. + * + * @param observables an array of observables + * @return a new progress value + */ + public static com.sk89q.worldguard.util.task.progress.Progress splitObservables(com.sk89q.worldguard.util.task.progress.ProgressObservable... observables) { + return splitObservables(Arrays.asList(observables)); + } + + /** + * Create a new progress object with progress split equally between the + * given {@link com.sk89q.worldguard.util.task.progress.ProgressObservable}s. + * + * @param observables a collection of observables + * @return a new progress value + */ + public static com.sk89q.worldguard.util.task.progress.Progress splitObservables(Collection observables) { + int count = 0; + double total = 0; + + for (ProgressObservable observable : observables) { + com.sk89q.worldguard.util.task.progress.Progress p = observable.getProgress(); + if (p.isIndeterminate()) { + return indeterminate(); + } + total += p.getProgress(); + } + + return of(total / count); + } + + private static final com.sk89q.worldguard.util.task.progress.Progress COMPLETED = of(1); + + private static final com.sk89q.worldguard.util.task.progress.Progress INDETERMINATE = new com.sk89q.worldguard.util.task.progress.Progress() { + @Override + public boolean isIndeterminate() { + return true; + } + + @Override + public double getProgress() { + return 0; + } + }; + +} diff --git a/src/main/java/com/sk89q/worldguard/util/task/progress/ProgressIterator.java b/src/main/java/com/sk89q/worldguard/util/task/progress/ProgressIterator.java new file mode 100644 index 00000000..0500afcc --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/util/task/progress/ProgressIterator.java @@ -0,0 +1,100 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.util.task.progress; + +import java.util.Iterator; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * An iterator that keeps track of how many entries have been visited and + * calculates a "percent completed" using a provided total count. + * + *

The returned progress percentage will always be between 0 or 1 + * (inclusive). If the iterator returns more entries than the total count, + * then 100% will be returned for the progress.

+ * + * @param the type + */ +public class ProgressIterator implements Iterator, ProgressObservable { + + private final Iterator iterator; + private final int count; + private int visited = 0; + + /** + * Create a new instance. + * + * @param iterator the iterator + * @param count the count + */ + private ProgressIterator(Iterator iterator, int count) { + checkNotNull(iterator); + this.iterator = iterator; + this.count = count; + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public V next() { + V value = iterator.next(); + visited++; + return value; + } + + @Override + public void remove() { + iterator.remove(); + } + + @Override + public Progress getProgress() { + return Progress.of(count > 0 ? Math.min(1, Math.max(0, (visited / (double) count))) : 1); + } + + /** + * Create a new instance. + * + * @param iterator the iterator + * @param count the number of objects + * @param the type + * @return an instance + */ + public static com.sk89q.worldguard.util.task.progress.ProgressIterator create(Iterator iterator, int count) { + return new com.sk89q.worldguard.util.task.progress.ProgressIterator(iterator, count); + } + + /** + * Create a new instance from a list. + * + * @param list a list + * @param the type + * @return an instance + */ + public static com.sk89q.worldguard.util.task.progress.ProgressIterator create(List list) { + return create(list.iterator(), list.size()); + } + +} diff --git a/src/main/java/com/sk89q/worldguard/util/task/progress/ProgressObservable.java b/src/main/java/com/sk89q/worldguard/util/task/progress/ProgressObservable.java new file mode 100644 index 00000000..b43dc44d --- /dev/null +++ b/src/main/java/com/sk89q/worldguard/util/task/progress/ProgressObservable.java @@ -0,0 +1,34 @@ +/* + * WorldGuard, a suite of tools for Minecraft + * Copyright (C) sk89q + * Copyright (C) WorldGuard team and contributors + * + * 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 Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldguard.util.task.progress; + +/** + * An object that is able to report on its progress. + */ +public interface ProgressObservable { + + /** + * Get the current percentage of completion. + * + * @return a progress object + */ + Progress getProgress(); + +}