From 78c7e5cf1455ae708a49360504fc0fd611572a3f Mon Sep 17 00:00:00 2001 From: crafter23456 <64259198+crafter23456@users.noreply.github.com> Date: Fri, 8 Apr 2022 16:59:34 +0200 Subject: [PATCH 1/2] remove unused commands --- .../java/com/google/common/base/Objects.java | 451 ----- .../common/util/concurrent/Futures.java | 1670 ----------------- .../common/util/concurrent/MoreExecutors.java | 1172 ------------ .../command/defaults/AchievementCommand.java | 188 -- .../bukkit/command/defaults/BanCommand.java | 56 - .../bukkit/command/defaults/BanIpCommand.java | 78 - .../command/defaults/BanListCommand.java | 72 - .../bukkit/command/defaults/ClearCommand.java | 115 -- .../defaults/DefaultGameModeCommand.java | 71 - .../bukkit/command/defaults/DeopCommand.java | 63 - .../command/defaults/DifficultyCommand.java | 82 - .../command/defaults/EffectCommand.java | 120 -- .../command/defaults/EnchantCommand.java | 170 -- .../bukkit/command/defaults/ExpCommand.java | 90 - .../command/defaults/GameModeCommand.java | 101 - .../command/defaults/GameRuleCommand.java | 89 - .../bukkit/command/defaults/GiveCommand.java | 130 -- .../bukkit/command/defaults/KickCommand.java | 60 - .../bukkit/command/defaults/KillCommand.java | 51 - .../bukkit/command/defaults/ListCommand.java | 55 - .../bukkit/command/defaults/MeCommand.java | 36 - .../bukkit/command/defaults/OpCommand.java | 76 - .../command/defaults/PardonCommand.java | 57 - .../command/defaults/PardonIpCommand.java | 53 - .../command/defaults/PlaySoundCommand.java | 88 - .../bukkit/command/defaults/SaveCommand.java | 47 - .../command/defaults/SaveOffCommand.java | 42 - .../command/defaults/SaveOnCommand.java | 42 - .../bukkit/command/defaults/SayCommand.java | 61 - .../command/defaults/ScoreboardCommand.java | 618 ------ .../bukkit/command/defaults/SeedCommand.java | 42 - .../defaults/SetIdleTimeoutCommand.java | 54 - .../defaults/SetWorldSpawnCommand.java | 80 - .../command/defaults/SpawnpointCommand.java | 88 - .../defaults/SpreadPlayersCommand.java | 266 --- .../bukkit/command/defaults/StopCommand.java | 49 - .../command/defaults/TeleportCommand.java | 125 -- .../bukkit/command/defaults/TellCommand.java | 61 - .../command/defaults/TestForCommand.java | 38 - .../bukkit/command/defaults/TimeCommand.java | 89 - .../defaults/ToggleDownfallCommand.java | 57 - .../command/defaults/WeatherCommand.java | 74 - .../command/defaults/WhitelistCommand.java | 128 -- .../org/bukkit/enchantments/Enchantment.java | 2 - 44 files changed, 7157 deletions(-) delete mode 100644 NachoSpigot-API/src/main/java/com/google/common/base/Objects.java delete mode 100644 NachoSpigot-API/src/main/java/com/google/common/util/concurrent/Futures.java delete mode 100644 NachoSpigot-API/src/main/java/com/google/common/util/concurrent/MoreExecutors.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/AchievementCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/BanCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/BanIpCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/BanListCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/ClearCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/DefaultGameModeCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/DeopCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/DifficultyCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/EffectCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/EnchantCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/ExpCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/GameModeCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/GameRuleCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/GiveCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/KickCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/KillCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/ListCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/MeCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/OpCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/PardonCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/PardonIpCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/PlaySoundCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SaveCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SaveOffCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SaveOnCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SayCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/ScoreboardCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SeedCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SetIdleTimeoutCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SetWorldSpawnCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SpawnpointCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SpreadPlayersCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/StopCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/TeleportCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/TellCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/TestForCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/TimeCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/ToggleDownfallCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/WeatherCommand.java delete mode 100644 NachoSpigot-API/src/main/java/org/bukkit/command/defaults/WhitelistCommand.java diff --git a/NachoSpigot-API/src/main/java/com/google/common/base/Objects.java b/NachoSpigot-API/src/main/java/com/google/common/base/Objects.java deleted file mode 100644 index 0101907a6..000000000 --- a/NachoSpigot-API/src/main/java/com/google/common/base/Objects.java +++ /dev/null @@ -1,451 +0,0 @@ -/* - * Copyright (C) 2007 The Guava Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.common.base; - -import com.google.common.annotations.GwtCompatible; - -import javax.annotation.CheckReturnValue; -import javax.annotation.Nullable; -import java.util.Arrays; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Helper functions that can operate on any {@code Object}. - * - *

See the Guava User Guide on writing - * {@code Object} methods with {@code Objects}. - * - * @author Laurence Gonsalves - * @since 2.0 (imported from Google Collections Library) - */ -@GwtCompatible -public final class Objects { - private Objects() {} - - /** - * Determines whether two possibly-null objects are equal. Returns: - * - *

- * - *

This assumes that any non-null objects passed to this function conform - * to the {@code equals()} contract. - */ - @CheckReturnValue - public static boolean equal(@Nullable Object a, @Nullable Object b) { - return java.util.Objects.equals(a, b); // Nacho - } - - /** - * Generates a hash code for multiple values. The hash code is generated by - * calling {@link Arrays#hashCode(Object[])}. Note that array arguments to - * this method, with the exception of a single Object array, do not get any - * special handling; their hash codes are based on identity and not contents. - * - *

This is useful for implementing {@link Object#hashCode()}. For example, - * in an object that has three properties, {@code x}, {@code y}, and - * {@code z}, one could write: - *

   {@code
-     *   public int hashCode() {
-     *     return Objects.hashCode(getX(), getY(), getZ());
-     *   }}
- * - *

Warning: When a single object is supplied, the returned hash code - * does not equal the hash code of that object. - */ - public static int hashCode(@Nullable Object... objects) { - return Arrays.hashCode(objects); - } - - // Nacho start - /** - * Creates an instance of {@link ToStringHelper}. - * - *

This is helpful for implementing {@link Object#toString()}. - * Specification by example:

   {@code
-     *   // Returns "ClassName{}"
-     *   Objects.toStringHelper(this)
-     *       .toString();
-     *
-     *   // Returns "ClassName{x=1}"
-     *   Objects.toStringHelper(this)
-     *       .add("x", 1)
-     *       .toString();
-     *
-     *   // Returns "MyObject{x=1}"
-     *   Objects.toStringHelper("MyObject")
-     *       .add("x", 1)
-     *       .toString();
-     *
-     *   // Returns "ClassName{x=1, y=foo}"
-     *   Objects.toStringHelper(this)
-     *       .add("x", 1)
-     *       .add("y", "foo")
-     *       .toString();
-     *
-     *   // Returns "ClassName{x=1}"
-     *   Objects.toStringHelper(this)
-     *       .omitNullValues()
-     *       .add("x", 1)
-     *       .add("y", null)
-     *       .toString();
-     *   }}
- * - *

Note that in GWT, class names are often obfuscated. - * - * @param self the object to generate the string for (typically {@code this}), - * used only for its class name - * @since 2.0 - * @deprecated replaced by {@link MoreObjects#toStringHelper(Object)} - * @see MoreObjects#toStringHelper(Object) - */ - @Deprecated - public static ToStringHelper toStringHelper(Object self) { - return new ToStringHelper(simpleName(self.getClass())); - } - - /** - * Creates an instance of {@link ToStringHelper} in the same manner as - * {@link Objects#toStringHelper(Object)}, but using the name of {@code clazz} - * instead of using an instance's {@link Object#getClass()}. - * - *

Note that in GWT, class names are often obfuscated. - * - * @param clazz the {@link Class} of the instance - * @since 7.0 (source-compatible since 2.0) - * @deprecated replaced by {@link MoreObjects#toStringHelper(Class)} - * @see MoreObjects#toStringHelper(Class) - */ - @Deprecated - public static ToStringHelper toStringHelper(Class clazz) { - return new ToStringHelper(simpleName(clazz)); - } - - /** - * Creates an instance of {@link ToStringHelper} in the same manner as - * {@link Objects#toStringHelper(Object)}, but using {@code className} instead - * of using an instance's {@link Object#getClass()}. - * - * @param className the name of the instance type - * @since 7.0 (source-compatible since 2.0) - * @deprecated replaced by {@link MoreObjects#toStringHelper(String)} - * @see MoreObjects#toStringHelper(String) - */ - @Deprecated - public static ToStringHelper toStringHelper(String className) { - return new ToStringHelper(className); - } - - /** - * {@link Class#getSimpleName()} is not GWT compatible yet, so we - * provide our own implementation. - * @deprecated {@link Class#getSimpleName()} is now GWT compatible, use it instead - * @see Class#getSimpleName() - */ - @Deprecated - private static String simpleName(Class clazz) { - String name = clazz.getName(); - - // the nth anonymous class has a class name ending in "Outer$n" - // and local inner classes have names ending in "Outer.$1Inner" - name = name.replaceAll("\\$[0-9]+", "\\$"); - - // we want the name of the inner class all by its lonesome - int start = name.lastIndexOf('$'); - - // if this isn't an inner class, just find the start of the - // top level class name. - if (start == -1) { - start = name.lastIndexOf('.'); - } - return name.substring(start + 1); - } - - /** - * Returns the first of two given parameters that is not {@code null}, if - * either is, or otherwise throws a {@link NullPointerException}. - * - *

Note: if {@code first} is represented as an {@link Optional}, - * this can be accomplished with - * {@linkplain Optional#or(Object) first.or(second)}. - * That approach also allows for lazy evaluation of the fallback instance, - * using {@linkplain Optional#or(Supplier) first.or(Supplier)}. - * - * @return {@code first} if {@code first} is not {@code null}, or - * {@code second} if {@code first} is {@code null} and {@code second} is - * not {@code null} - * @throws NullPointerException if both {@code first} and {@code second} were - * {@code null} - * @since 3.0 - * @deprecated replaced by {@link MoreObjects#firstNonNull(Object, Object)} - * @see MoreObjects#firstNonNull(Object, Object) - */ - @Deprecated - public static T firstNonNull(@Nullable T first, @Nullable T second) { - return first != null ? first : checkNotNull(second); - } - - /** - * Support class for {@link Objects#toStringHelper}. - * - * @author Jason Lee - * @since 2.0 - * @deprecated replaced by {@link MoreObjects.ToStringHelper} - * @see MoreObjects.ToStringHelper - */ - @Deprecated - public static final class ToStringHelper { - private final String className; - private ValueHolder holderHead = new ValueHolder(); - private ValueHolder holderTail = holderHead; - private boolean omitNullValues = false; - - /** - * Use {@link Objects#toStringHelper(Object)} to create an instance. - */ - private ToStringHelper(String className) { - this.className = checkNotNull(className); - } - - /** - * Configures the {@link ToStringHelper} so {@link #toString()} will ignore - * properties with null value. The order of calling this method, relative - * to the {@code add()}/{@code addValue()} methods, is not significant. - * - * @since 12.0 - */ - public ToStringHelper omitNullValues() { - omitNullValues = true; - return this; - } - - /** - * Adds a name/value pair to the formatted output in {@code name=value} - * format. If {@code value} is {@code null}, the string {@code "null"} - * is used, unless {@link #omitNullValues()} is called, in which case this - * name/value pair will not be added. - */ - public ToStringHelper add(String name, @Nullable Object value) { - return addHolder(name, value); - } - - /** - * Adds a name/value pair to the formatted output in {@code name=value} - * format. - * - * @since 11.0 (source-compatible since 2.0) - */ - public ToStringHelper add(String name, boolean value) { - return addHolder(name, String.valueOf(value)); - } - - /** - * Adds a name/value pair to the formatted output in {@code name=value} - * format. - * - * @since 11.0 (source-compatible since 2.0) - */ - public ToStringHelper add(String name, char value) { - return addHolder(name, String.valueOf(value)); - } - - /** - * Adds a name/value pair to the formatted output in {@code name=value} - * format. - * - * @since 11.0 (source-compatible since 2.0) - */ - public ToStringHelper add(String name, double value) { - return addHolder(name, String.valueOf(value)); - } - - /** - * Adds a name/value pair to the formatted output in {@code name=value} - * format. - * - * @since 11.0 (source-compatible since 2.0) - */ - public ToStringHelper add(String name, float value) { - return addHolder(name, String.valueOf(value)); - } - - /** - * Adds a name/value pair to the formatted output in {@code name=value} - * format. - * - * @since 11.0 (source-compatible since 2.0) - */ - public ToStringHelper add(String name, int value) { - return addHolder(name, String.valueOf(value)); - } - - /** - * Adds a name/value pair to the formatted output in {@code name=value} - * format. - * - * @since 11.0 (source-compatible since 2.0) - */ - public ToStringHelper add(String name, long value) { - return addHolder(name, String.valueOf(value)); - } - - /** - * Adds an unnamed value to the formatted output. - * - *

It is strongly encouraged to use {@link #add(String, Object)} instead - * and give value a readable name. - */ - public ToStringHelper addValue(@Nullable Object value) { - return addHolder(value); - } - - /** - * Adds an unnamed value to the formatted output. - * - *

It is strongly encouraged to use {@link #add(String, boolean)} instead - * and give value a readable name. - * - * @since 11.0 (source-compatible since 2.0) - */ - public ToStringHelper addValue(boolean value) { - return addHolder(String.valueOf(value)); - } - - /** - * Adds an unnamed value to the formatted output. - * - *

It is strongly encouraged to use {@link #add(String, char)} instead - * and give value a readable name. - * - * @since 11.0 (source-compatible since 2.0) - */ - public ToStringHelper addValue(char value) { - return addHolder(String.valueOf(value)); - } - - /** - * Adds an unnamed value to the formatted output. - * - *

It is strongly encouraged to use {@link #add(String, double)} instead - * and give value a readable name. - * - * @since 11.0 (source-compatible since 2.0) - */ - public ToStringHelper addValue(double value) { - return addHolder(String.valueOf(value)); - } - - /** - * Adds an unnamed value to the formatted output. - * - *

It is strongly encouraged to use {@link #add(String, float)} instead - * and give value a readable name. - * - * @since 11.0 (source-compatible since 2.0) - */ - public ToStringHelper addValue(float value) { - return addHolder(String.valueOf(value)); - } - - /** - * Adds an unnamed value to the formatted output. - * - *

It is strongly encouraged to use {@link #add(String, int)} instead - * and give value a readable name. - * - * @since 11.0 (source-compatible since 2.0) - */ - public ToStringHelper addValue(int value) { - return addHolder(String.valueOf(value)); - } - - /** - * Adds an unnamed value to the formatted output. - * - *

It is strongly encouraged to use {@link #add(String, long)} instead - * and give value a readable name. - * - * @since 11.0 (source-compatible since 2.0) - */ - public ToStringHelper addValue(long value) { - return addHolder(String.valueOf(value)); - } - - /** - * Returns a string in the format specified by {@link - * Objects#toStringHelper(Object)}. - * - *

After calling this method, you can keep adding more properties to later - * call toString() again and get a more complete representation of the - * same object; but properties cannot be removed, so this only allows - * limited reuse of the helper instance. The helper allows duplication of - * properties (multiple name/value pairs with the same name can be added). - */ - @Override public String toString() { - // create a copy to keep it consistent in case value changes - boolean omitNullValuesSnapshot = omitNullValues; - String nextSeparator = ""; - StringBuilder builder = new StringBuilder(32).append(className) - .append('{'); - for (ValueHolder valueHolder = holderHead.next; valueHolder != null; - valueHolder = valueHolder.next) { - if (!omitNullValuesSnapshot || valueHolder.value != null) { - builder.append(nextSeparator); - nextSeparator = ", "; - - if (valueHolder.name != null) { - builder.append(valueHolder.name).append('='); - } - builder.append(valueHolder.value); - } - } - return builder.append('}').toString(); - } - - private ValueHolder addHolder() { - ValueHolder valueHolder = new ValueHolder(); - holderTail = holderTail.next = valueHolder; - return valueHolder; - } - - private ToStringHelper addHolder(@Nullable Object value) { - ValueHolder valueHolder = addHolder(); - valueHolder.value = value; - return this; - } - - private ToStringHelper addHolder(String name, @Nullable Object value) { - ValueHolder valueHolder = addHolder(); - valueHolder.value = value; - valueHolder.name = checkNotNull(name); - return this; - } - - private static final class ValueHolder { - String name; - Object value; - ValueHolder next; - } - } - // Nacho end -} \ No newline at end of file diff --git a/NachoSpigot-API/src/main/java/com/google/common/util/concurrent/Futures.java b/NachoSpigot-API/src/main/java/com/google/common/util/concurrent/Futures.java deleted file mode 100644 index 03dc028d9..000000000 --- a/NachoSpigot-API/src/main/java/com/google/common/util/concurrent/Futures.java +++ /dev/null @@ -1,1670 +0,0 @@ -/* - * Copyright (C) 2006 The Guava Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.common.util.concurrent; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; -import static com.google.common.util.concurrent.Internal.toNanosSaturated; -import static com.google.common.util.concurrent.MoreExecutors.directExecutor; -import static com.google.common.util.concurrent.Uninterruptibles.getUninterruptibly; -import static java.util.Objects.requireNonNull; - -import com.google.common.annotations.Beta; -import com.google.common.annotations.GwtCompatible; -import com.google.common.annotations.GwtIncompatible; -import com.google.common.base.Function; -import com.google.common.base.MoreObjects; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.common.util.concurrent.CollectionFuture.ListFuture; -import com.google.common.util.concurrent.ImmediateFuture.ImmediateCancelledFuture; -import com.google.common.util.concurrent.ImmediateFuture.ImmediateFailedFuture; -import com.google.common.util.concurrent.internal.InternalFutureFailureAccess; -import com.google.common.util.concurrent.internal.InternalFutures; -import com.google.errorprone.annotations.CanIgnoreReturnValue; -import java.time.Duration; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; -import java.util.concurrent.Future; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; -import javax.annotation.CheckForNull; -import org.checkerframework.checker.nullness.qual.Nullable; - -/** - * Static utility methods pertaining to the {@link Future} interface. - * - *

Many of these methods use the {@link ListenableFuture} API; consult the Guava User Guide - * article on {@code - * ListenableFuture}. - * - *

The main purpose of {@code ListenableFuture} is to help you chain together a graph of - * asynchronous operations. You can chain them together manually with calls to methods like {@link - * Futures#transform(ListenableFuture, Function, Executor) Futures.transform}, but you will often - * find it easier to use a framework. Frameworks automate the process, often adding features like - * monitoring, debugging, and cancellation. Examples of frameworks include: - * - *

- * - *

If you do chain your operations manually, you may want to use {@link FluentFuture}. - * - * @author Kevin Bourrillion - * @author Nishant Thakkar - * @author Sven Mawson - * @since 1.0 - */ -@GwtCompatible(emulated = true) -@ElementTypesAreNonnullByDefault -public final class Futures extends GwtFuturesCatchingSpecialization { - - // A note on memory visibility. - // Many of the utilities in this class (transform, withFallback, withTimeout, asList, combine) - // have two requirements that significantly complicate their design. - // 1. Cancellation should propagate from the returned future to the input future(s). - // 2. The returned futures shouldn't unnecessarily 'pin' their inputs after completion. - // - // A consequence of these requirements is that the delegate futures cannot be stored in - // final fields. - // - // For simplicity the rest of this description will discuss Futures.catching since it is the - // simplest instance, though very similar descriptions apply to many other classes in this file. - // - // In the constructor of AbstractCatchingFuture, the delegate future is assigned to a field - // 'inputFuture'. That field is non-final and non-volatile. There are 2 places where the - // 'inputFuture' field is read and where we will have to consider visibility of the write - // operation in the constructor. - // - // 1. In the listener that performs the callback. In this case it is fine since inputFuture is - // assigned prior to calling addListener, and addListener happens-before any invocation of the - // listener. Notably, this means that 'volatile' is unnecessary to make 'inputFuture' visible - // to the listener. - // - // 2. In done() where we may propagate cancellation to the input. In this case it is _not_ fine. - // There is currently nothing that enforces that the write to inputFuture in the constructor is - // visible to done(). This is because there is no happens before edge between the write and a - // (hypothetical) unsafe read by our caller. Note: adding 'volatile' does not fix this issue, - // it would just add an edge such that if done() observed non-null, then it would also - // definitely observe all earlier writes, but we still have no guarantee that done() would see - // the inital write (just stronger guarantees if it does). - // - // See: http://cs.oswego.edu/pipermail/concurrency-interest/2015-January/013800.html - // For a (long) discussion about this specific issue and the general futility of life. - // - // For the time being we are OK with the problem discussed above since it requires a caller to - // introduce a very specific kind of data-race. And given the other operations performed by these - // methods that involve volatile read/write operations, in practice there is no issue. Also, the - // way in such a visibility issue would surface is most likely as a failure of cancel() to - // propagate to the input. Cancellation propagation is fundamentally racy so this is fine. - // - // Future versions of the JMM may revise safe construction semantics in such a way that we can - // safely publish these objects and we won't need this whole discussion. - // TODO(user,lukes): consider adding volatile to all these fields since in current known JVMs - // that should resolve the issue. This comes at the cost of adding more write barriers to the - // implementations. - - private Futures() {} - - /** - * Creates a {@code ListenableFuture} which has its value set immediately upon construction. The - * getters just return the value. This {@code Future} can't be canceled or timed out and its - * {@code isDone()} method always returns {@code true}. - */ - public static ListenableFuture immediateFuture( - @ParametricNullness V value) { - if (value == null) { - // This cast is safe because null is assignable to V for all V (i.e. it is bivariant) - @SuppressWarnings("unchecked") - ListenableFuture typedNull = (ListenableFuture) ImmediateFuture.NULL; - return typedNull; - } - return new ImmediateFuture<>(value); - } - - /** - * Returns a successful {@code ListenableFuture}. This method is equivalent to {@code - * immediateFuture(null)} except that it is restricted to produce futures of type {@code Void}. - * - * @since 29.0 - */ - @SuppressWarnings("unchecked") - public static ListenableFuture<@Nullable Void> immediateVoidFuture() { - return (ListenableFuture<@Nullable Void>) ImmediateFuture.NULL; - } - - /** - * Returns a {@code ListenableFuture} which has an exception set immediately upon construction. - * - *

The returned {@code Future} can't be cancelled, and its {@code isDone()} method always - * returns {@code true}. Calling {@code get()} will immediately throw the provided {@code - * Throwable} wrapped in an {@code ExecutionException}. - */ - public static ListenableFuture immediateFailedFuture( - Throwable throwable) { - checkNotNull(throwable); - return new ImmediateFailedFuture(throwable); - } - - /** - * Creates a {@code ListenableFuture} which is cancelled immediately upon construction, so that - * {@code isCancelled()} always returns {@code true}. - * - * @since 14.0 - */ - public static ListenableFuture immediateCancelledFuture() { - return new ImmediateCancelledFuture(); - } - - /** - * Executes {@code callable} on the specified {@code executor}, returning a {@code Future}. - * - * @throws RejectedExecutionException if the task cannot be scheduled for execution - * @since 28.2 - */ - public static ListenableFuture submit( - Callable callable, Executor executor) { - TrustedListenableFutureTask task = TrustedListenableFutureTask.create(callable); - executor.execute(task); - return task; - } - - /** - * Executes {@code runnable} on the specified {@code executor}, returning a {@code Future} that - * will complete after execution. - * - * @throws RejectedExecutionException if the task cannot be scheduled for execution - * @since 28.2 - */ - public static ListenableFuture<@Nullable Void> submit(Runnable runnable, Executor executor) { - TrustedListenableFutureTask<@Nullable Void> task = - TrustedListenableFutureTask.create(runnable, null); - executor.execute(task); - return task; - } - - /** - * Executes {@code callable} on the specified {@code executor}, returning a {@code Future}. - * - * @throws RejectedExecutionException if the task cannot be scheduled for execution - * @since 23.0 - */ - public static ListenableFuture submitAsync( - AsyncCallable callable, Executor executor) { - TrustedListenableFutureTask task = TrustedListenableFutureTask.create(callable); - executor.execute(task); - return task; - } - - /** - * Schedules {@code callable} on the specified {@code executor}, returning a {@code Future}. - * - * @throws RejectedExecutionException if the task cannot be scheduled for execution - * @since 28.0 - */ - @GwtIncompatible // java.util.concurrent.ScheduledExecutorService - // TODO(cpovirk): Return ListenableScheduledFuture? - public static ListenableFuture scheduleAsync( - AsyncCallable callable, Duration delay, ScheduledExecutorService executorService) { - return scheduleAsync(callable, toNanosSaturated(delay), TimeUnit.NANOSECONDS, executorService); - } - - /** - * Schedules {@code callable} on the specified {@code executor}, returning a {@code Future}. - * - * @throws RejectedExecutionException if the task cannot be scheduled for execution - * @since 23.0 - */ - @GwtIncompatible // java.util.concurrent.ScheduledExecutorService - @SuppressWarnings("GoodTime") // should accept a java.time.Duration - // TODO(cpovirk): Return ListenableScheduledFuture? - public static ListenableFuture scheduleAsync( - AsyncCallable callable, - long delay, - TimeUnit timeUnit, - ScheduledExecutorService executorService) { - TrustedListenableFutureTask task = TrustedListenableFutureTask.create(callable); - final Future scheduled = executorService.schedule(task, delay, timeUnit); - task.addListener( - new Runnable() { - @Override - public void run() { - // Don't want to interrupt twice - scheduled.cancel(false); - } - }, - directExecutor()); - return task; - } - - /** - * Returns a {@code Future} whose result is taken from the given primary {@code input} or, if the - * primary input fails with the given {@code exceptionType}, from the result provided by the - * {@code fallback}. {@link Function#apply} is not invoked until the primary input has failed, so - * if the primary input succeeds, it is never invoked. If, during the invocation of {@code - * fallback}, an exception is thrown, this exception is used as the result of the output {@code - * Future}. - * - *

Usage example: - * - *

{@code
-   * ListenableFuture fetchCounterFuture = ...;
-   *
-   * // Falling back to a zero counter in case an exception happens when
-   * // processing the RPC to fetch counters.
-   * ListenableFuture faultTolerantFuture = Futures.catching(
-   *     fetchCounterFuture, FetchException.class, x -> 0, directExecutor());
-   * }
- * - *

When selecting an executor, note that {@code directExecutor} is dangerous in some cases. See - * the warnings the {@link MoreExecutors#directExecutor} documentation. - * - * @param input the primary input {@code Future} - * @param exceptionType the exception type that triggers use of {@code fallback}. The exception - * type is matched against the input's exception. "The input's exception" means the cause of - * the {@link ExecutionException} thrown by {@code input.get()} or, if {@code get()} throws a - * different kind of exception, that exception itself. To avoid hiding bugs and other - * unrecoverable errors, callers should prefer more specific types, avoiding {@code - * Throwable.class} in particular. - * @param fallback the {@link Function} to be called if {@code input} fails with the expected - * exception type. The function's argument is the input's exception. "The input's exception" - * means the cause of the {@link ExecutionException} thrown by {@code input.get()} or, if - * {@code get()} throws a different kind of exception, that exception itself. - * @param executor the executor that runs {@code fallback} if {@code input} fails - * @since 19.0 - */ - @Beta - @Partially.GwtIncompatible("AVAILABLE but requires exceptionType to be Throwable.class") - public static ListenableFuture catching( - ListenableFuture input, - Class exceptionType, - Function fallback, - Executor executor) { - return AbstractCatchingFuture.create(input, exceptionType, fallback, executor); - } - - /** - * Returns a {@code Future} whose result is taken from the given primary {@code input} or, if the - * primary input fails with the given {@code exceptionType}, from the result provided by the - * {@code fallback}. {@link AsyncFunction#apply} is not invoked until the primary input has - * failed, so if the primary input succeeds, it is never invoked. If, during the invocation of - * {@code fallback}, an exception is thrown, this exception is used as the result of the output - * {@code Future}. - * - *

Usage examples: - * - *

{@code
-   * ListenableFuture fetchCounterFuture = ...;
-   *
-   * // Falling back to a zero counter in case an exception happens when
-   * // processing the RPC to fetch counters.
-   * ListenableFuture faultTolerantFuture = Futures.catchingAsync(
-   *     fetchCounterFuture, FetchException.class, x -> immediateFuture(0), directExecutor());
-   * }
- * - *

The fallback can also choose to propagate the original exception when desired: - * - *

{@code
-   * ListenableFuture fetchCounterFuture = ...;
-   *
-   * // Falling back to a zero counter only in case the exception was a
-   * // TimeoutException.
-   * ListenableFuture faultTolerantFuture = Futures.catchingAsync(
-   *     fetchCounterFuture,
-   *     FetchException.class,
-   *     e -> {
-   *       if (omitDataOnFetchFailure) {
-   *         return immediateFuture(0);
-   *       }
-   *       throw e;
-   *     },
-   *     directExecutor());
-   * }
- * - *

When selecting an executor, note that {@code directExecutor} is dangerous in some cases. See - * the warnings the {@link MoreExecutors#directExecutor} documentation. - * - * @param input the primary input {@code Future} - * @param exceptionType the exception type that triggers use of {@code fallback}. The exception - * type is matched against the input's exception. "The input's exception" means the cause of - * the {@link ExecutionException} thrown by {@code input.get()} or, if {@code get()} throws a - * different kind of exception, that exception itself. To avoid hiding bugs and other - * unrecoverable errors, callers should prefer more specific types, avoiding {@code - * Throwable.class} in particular. - * @param fallback the {@link AsyncFunction} to be called if {@code input} fails with the expected - * exception type. The function's argument is the input's exception. "The input's exception" - * means the cause of the {@link ExecutionException} thrown by {@code input.get()} or, if - * {@code get()} throws a different kind of exception, that exception itself. - * @param executor the executor that runs {@code fallback} if {@code input} fails - * @since 19.0 (similar functionality in 14.0 as {@code withFallback}) - */ - @Beta - @Partially.GwtIncompatible("AVAILABLE but requires exceptionType to be Throwable.class") - public static ListenableFuture catchingAsync( - ListenableFuture input, - Class exceptionType, - AsyncFunction fallback, - Executor executor) { - return AbstractCatchingFuture.create(input, exceptionType, fallback, executor); - } - - /** - * Returns a future that delegates to another but will finish early (via a {@link - * TimeoutException} wrapped in an {@link ExecutionException}) if the specified duration expires. - * - *

The delegate future is interrupted and cancelled if it times out. - * - * @param delegate The future to delegate to. - * @param time when to timeout the future - * @param scheduledExecutor The executor service to enforce the timeout. - * @since 28.0 - */ - @Beta - @GwtIncompatible // java.util.concurrent.ScheduledExecutorService - public static ListenableFuture withTimeout( - ListenableFuture delegate, Duration time, ScheduledExecutorService scheduledExecutor) { - return withTimeout(delegate, toNanosSaturated(time), TimeUnit.NANOSECONDS, scheduledExecutor); - } - - /** - * Returns a future that delegates to another but will finish early (via a {@link - * TimeoutException} wrapped in an {@link ExecutionException}) if the specified duration expires. - * - *

The delegate future is interrupted and cancelled if it times out. - * - * @param delegate The future to delegate to. - * @param time when to timeout the future - * @param unit the time unit of the time parameter - * @param scheduledExecutor The executor service to enforce the timeout. - * @since 19.0 - */ - @Beta - @GwtIncompatible // java.util.concurrent.ScheduledExecutorService - @SuppressWarnings("GoodTime") // should accept a java.time.Duration - public static ListenableFuture withTimeout( - ListenableFuture delegate, - long time, - TimeUnit unit, - ScheduledExecutorService scheduledExecutor) { - if (delegate.isDone()) { - return delegate; - } - return TimeoutFuture.create(delegate, time, unit, scheduledExecutor); - } - - /** - * Returns a new {@code Future} whose result is asynchronously derived from the result of the - * given {@code Future}. If the given {@code Future} fails, the returned {@code Future} fails with - * the same exception (and the function is not invoked). - * - *

More precisely, the returned {@code Future} takes its result from a {@code Future} produced - * by applying the given {@code AsyncFunction} to the result of the original {@code Future}. - * Example usage: - * - *

{@code
-   * ListenableFuture rowKeyFuture = indexService.lookUp(query);
-   * ListenableFuture queryFuture =
-   *     transformAsync(rowKeyFuture, dataService::readFuture, executor);
-   * }
- * - *

When selecting an executor, note that {@code directExecutor} is dangerous in some cases. See - * the warnings the {@link MoreExecutors#directExecutor} documentation. - * - *

The returned {@code Future} attempts to keep its cancellation state in sync with that of the - * input future and that of the future returned by the chain function. That is, if the returned - * {@code Future} is cancelled, it will attempt to cancel the other two, and if either of the - * other two is cancelled, the returned {@code Future} will receive a callback in which it will - * attempt to cancel itself. - * - * @param input The future to transform - * @param function A function to transform the result of the input future to the result of the - * output future - * @param executor Executor to run the function in. - * @return A future that holds result of the function (if the input succeeded) or the original - * input's failure (if not) - * @since 19.0 (in 11.0 as {@code transform}) - */ - @Beta - public static - ListenableFuture transformAsync( - ListenableFuture input, - AsyncFunction function, - Executor executor) { - return AbstractTransformFuture.create(input, function, executor); - } - - /** - * Returns a new {@code Future} whose result is derived from the result of the given {@code - * Future}. If {@code input} fails, the returned {@code Future} fails with the same exception (and - * the function is not invoked). Example usage: - * - *

{@code
-   * ListenableFuture queryFuture = ...;
-   * ListenableFuture> rowsFuture =
-   *     transform(queryFuture, QueryResult::getRows, executor);
-   * }
- * - *

When selecting an executor, note that {@code directExecutor} is dangerous in some cases. See - * the warnings the {@link MoreExecutors#directExecutor} documentation. - * - *

The returned {@code Future} attempts to keep its cancellation state in sync with that of the - * input future. That is, if the returned {@code Future} is cancelled, it will attempt to cancel - * the input, and if the input is cancelled, the returned {@code Future} will receive a callback - * in which it will attempt to cancel itself. - * - *

An example use of this method is to convert a serializable object returned from an RPC into - * a POJO. - * - * @param input The future to transform - * @param function A Function to transform the results of the provided future to the results of - * the returned future. - * @param executor Executor to run the function in. - * @return A future that holds result of the transformation. - * @since 9.0 (in 2.0 as {@code compose}) - */ - @Beta - public static - ListenableFuture transform( - ListenableFuture input, Function function, Executor executor) { - return AbstractTransformFuture.create(input, function, executor); - } - - /** - * Like {@link #transform(ListenableFuture, Function, Executor)} except that the transformation - * {@code function} is invoked on each call to {@link Future#get() get()} on the returned future. - * - *

The returned {@code Future} reflects the input's cancellation state directly, and any - * attempt to cancel the returned Future is likewise passed through to the input Future. - * - *

Note that calls to {@linkplain Future#get(long, TimeUnit) timed get} only apply the timeout - * to the execution of the underlying {@code Future}, not to the execution of the - * transformation function. - * - *

The primary audience of this method is callers of {@code transform} who don't have a {@code - * ListenableFuture} available and do not mind repeated, lazy function evaluation. - * - * @param input The future to transform - * @param function A Function to transform the results of the provided future to the results of - * the returned future. - * @return A future that returns the result of the transformation. - * @since 10.0 - */ - @Beta - @GwtIncompatible // TODO - public static Future lazyTransform( - final Future input, final Function function) { - checkNotNull(input); - checkNotNull(function); - return new Future() { - - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - return input.cancel(mayInterruptIfRunning); - } - - @Override - public boolean isCancelled() { - return input.isCancelled(); - } - - @Override - public boolean isDone() { - return input.isDone(); - } - - @Override - public O get() throws InterruptedException, ExecutionException { - return applyTransformation(input.get()); - } - - @Override - public O get(long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, TimeoutException { - return applyTransformation(input.get(timeout, unit)); - } - - private O applyTransformation(I input) throws ExecutionException { - try { - return function.apply(input); - } catch (Throwable t) { - throw new ExecutionException(t); - } - } - }; - } - - /** - * Creates a new {@code ListenableFuture} whose value is a list containing the values of all its - * input futures, if all succeed. - * - *

The list of results is in the same order as the input list. - * - *

This differs from {@link #successfulAsList(ListenableFuture[])} in that it will return a - * failed future if any of the items fails. - * - *

Canceling this future will attempt to cancel all the component futures, and if any of the - * provided futures fails or is canceled, this one is, too. - * - * @param futures futures to combine - * @return a future that provides a list of the results of the component futures - * @since 10.0 - */ - @Beta - @SafeVarargs - public static ListenableFuture> allAsList( - ListenableFuture... futures) { - ListenableFuture> nullable = - new ListFuture(ImmutableList.copyOf(futures), true); - // allAsList ensures that it fills the output list with V instances. - @SuppressWarnings("nullness") - ListenableFuture> nonNull = nullable; - return nonNull; - } - - /** - * Creates a new {@code ListenableFuture} whose value is a list containing the values of all its - * input futures, if all succeed. - * - *

The list of results is in the same order as the input list. - * - *

This differs from {@link #successfulAsList(Iterable)} in that it will return a failed future - * if any of the items fails. - * - *

Canceling this future will attempt to cancel all the component futures, and if any of the - * provided futures fails or is canceled, this one is, too. - * - * @param futures futures to combine - * @return a future that provides a list of the results of the component futures - * @since 10.0 - */ - @Beta - public static ListenableFuture> allAsList( - Iterable> futures) { - ListenableFuture> nullable = - new ListFuture(ImmutableList.copyOf(futures), true); - // allAsList ensures that it fills the output list with V instances. - @SuppressWarnings("nullness") - ListenableFuture> nonNull = nullable; - return nonNull; - } - - /** - * Creates a {@link FutureCombiner} that processes the completed futures whether or not they're - * successful. - * - *

Any failures from the input futures will not be propagated to the returned future. - * - * @since 20.0 - */ - @Beta - @SafeVarargs - public static FutureCombiner whenAllComplete( - ListenableFuture... futures) { - return new FutureCombiner(false, ImmutableList.copyOf(futures)); - } - - /** - * Creates a {@link FutureCombiner} that processes the completed futures whether or not they're - * successful. - * - *

Any failures from the input futures will not be propagated to the returned future. - * - * @since 20.0 - */ - @Beta - public static FutureCombiner whenAllComplete( - Iterable> futures) { - return new FutureCombiner(false, ImmutableList.copyOf(futures)); - } - - /** - * Creates a {@link FutureCombiner} requiring that all passed in futures are successful. - * - *

If any input fails, the returned future fails immediately. - * - * @since 20.0 - */ - @Beta - @SafeVarargs - public static FutureCombiner whenAllSucceed( - ListenableFuture... futures) { - return new FutureCombiner(true, ImmutableList.copyOf(futures)); - } - - /** - * Creates a {@link FutureCombiner} requiring that all passed in futures are successful. - * - *

If any input fails, the returned future fails immediately. - * - * @since 20.0 - */ - @Beta - public static FutureCombiner whenAllSucceed( - Iterable> futures) { - return new FutureCombiner(true, ImmutableList.copyOf(futures)); - } - - /** - * A helper to create a new {@code ListenableFuture} whose result is generated from a combination - * of input futures. - * - *

See {@link #whenAllComplete} and {@link #whenAllSucceed} for how to instantiate this class. - * - *

Example: - * - *

{@code
-   * final ListenableFuture loginDateFuture =
-   *     loginService.findLastLoginDate(username);
-   * final ListenableFuture> recentCommandsFuture =
-   *     recentCommandsService.findRecentCommands(username);
-   * ListenableFuture usageFuture =
-   *     Futures.whenAllSucceed(loginDateFuture, recentCommandsFuture)
-   *         .call(
-   *             () ->
-   *                 new UsageHistory(
-   *                     username,
-   *                     Futures.getDone(loginDateFuture),
-   *                     Futures.getDone(recentCommandsFuture)),
-   *             executor);
-   * }
- * - * @since 20.0 - */ - @Beta - @CanIgnoreReturnValue // TODO(cpovirk): Consider removing, especially if we provide run(Runnable) - @GwtCompatible - public static final class FutureCombiner { - private final boolean allMustSucceed; - private final ImmutableList> futures; - - private FutureCombiner( - boolean allMustSucceed, ImmutableList> futures) { - this.allMustSucceed = allMustSucceed; - this.futures = futures; - } - - /** - * Creates the {@link ListenableFuture} which will return the result of calling {@link - * AsyncCallable#call} in {@code combiner} when all futures complete, using the specified {@code - * executor}. - * - *

If the combiner throws a {@code CancellationException}, the returned future will be - * cancelled. - * - *

If the combiner throws an {@code ExecutionException}, the cause of the thrown {@code - * ExecutionException} will be extracted and returned as the cause of the new {@code - * ExecutionException} that gets thrown by the returned combined future. - * - *

Canceling this future will attempt to cancel all the component futures. - */ - public ListenableFuture callAsync( - AsyncCallable combiner, Executor executor) { - return new CombinedFuture(futures, allMustSucceed, executor, combiner); - } - - /** - * Creates the {@link ListenableFuture} which will return the result of calling {@link - * Callable#call} in {@code combiner} when all futures complete, using the specified {@code - * executor}. - * - *

If the combiner throws a {@code CancellationException}, the returned future will be - * cancelled. - * - *

If the combiner throws an {@code ExecutionException}, the cause of the thrown {@code - * ExecutionException} will be extracted and returned as the cause of the new {@code - * ExecutionException} that gets thrown by the returned combined future. - * - *

Canceling this future will attempt to cancel all the component futures. - */ - @CanIgnoreReturnValue // TODO(cpovirk): Remove this - public ListenableFuture call( - Callable combiner, Executor executor) { - return new CombinedFuture(futures, allMustSucceed, executor, combiner); - } - - /** - * Creates the {@link ListenableFuture} which will return the result of running {@code combiner} - * when all Futures complete. {@code combiner} will run using {@code executor}. - * - *

If the combiner throws a {@code CancellationException}, the returned future will be - * cancelled. - * - *

Canceling this Future will attempt to cancel all the component futures. - * - * @since 23.6 - */ - public ListenableFuture run(final Runnable combiner, Executor executor) { - return call( - new Callable<@Nullable Void>() { - @Override - @CheckForNull - public Void call() throws Exception { - combiner.run(); - return null; - } - }, - executor); - } - } - - /** - * Returns a {@code ListenableFuture} whose result is set from the supplied future when it - * completes. Cancelling the supplied future will also cancel the returned future, but cancelling - * the returned future will have no effect on the supplied future. - * - * @since 15.0 - */ - public static ListenableFuture nonCancellationPropagating( - ListenableFuture future) { - if (future.isDone()) { - return future; - } - NonCancellationPropagatingFuture output = new NonCancellationPropagatingFuture<>(future); - future.addListener(output, directExecutor()); - return output; - } - - /** A wrapped future that does not propagate cancellation to its delegate. */ - private static final class NonCancellationPropagatingFuture - extends AbstractFuture.TrustedFuture implements Runnable { - @CheckForNull private ListenableFuture delegate; - - NonCancellationPropagatingFuture(final ListenableFuture delegate) { - this.delegate = delegate; - } - - @Override - public void run() { - // This prevents cancellation from propagating because we don't call setFuture(delegate) until - // delegate is already done, so calling cancel() on this future won't affect it. - ListenableFuture localDelegate = delegate; - if (localDelegate != null) { - setFuture(localDelegate); - } - } - - @Override - @CheckForNull - protected String pendingToString() { - ListenableFuture localDelegate = delegate; - if (localDelegate != null) { - return "delegate=[" + localDelegate + "]"; - } - return null; - } - - @Override - protected void afterDone() { - delegate = null; - } - } - - /** - * Creates a new {@code ListenableFuture} whose value is a list containing the values of all its - * successful input futures. The list of results is in the same order as the input list, and if - * any of the provided futures fails or is canceled, its corresponding position will contain - * {@code null} (which is indistinguishable from the future having a successful value of {@code - * null}). - * - *

The list of results is in the same order as the input list. - * - *

This differs from {@link #allAsList(ListenableFuture[])} in that it's tolerant of failed - * futures for any of the items, representing them as {@code null} in the result list. - * - *

Canceling this future will attempt to cancel all the component futures. - * - * @param futures futures to combine - * @return a future that provides a list of the results of the component futures - * @since 10.0 - */ - @Beta - @SafeVarargs - public static ListenableFuture> successfulAsList( - ListenableFuture... futures) { - /* - * Another way to express this signature would be to bound by @NonNull and accept - * LF. That might be better: There's currently no difference between the - * outputs users get when calling this with and calling it with <@Nullable Foo>. The only - * difference is that calling it with won't work when an input Future has a @Nullable - * type. So why even make that error possible by giving callers the choice? - * - * On the other hand, the current signature is consistent with the similar allAsList method. And - * eventually this method may go away entirely in favor of an API like - * whenAllComplete().collectSuccesses(). That API would have a signature more like the current - * one. - */ - return new ListFuture(ImmutableList.copyOf(futures), false); - } - - /** - * Creates a new {@code ListenableFuture} whose value is a list containing the values of all its - * successful input futures. The list of results is in the same order as the input list, and if - * any of the provided futures fails or is canceled, its corresponding position will contain - * {@code null} (which is indistinguishable from the future having a successful value of {@code - * null}). - * - *

The list of results is in the same order as the input list. - * - *

This differs from {@link #allAsList(Iterable)} in that it's tolerant of failed futures for - * any of the items, representing them as {@code null} in the result list. - * - *

Canceling this future will attempt to cancel all the component futures. - * - * @param futures futures to combine - * @return a future that provides a list of the results of the component futures - * @since 10.0 - */ - @Beta - public static ListenableFuture> successfulAsList( - Iterable> futures) { - return new ListFuture(ImmutableList.copyOf(futures), false); - } - - /** - * Returns a list of delegate futures that correspond to the futures received in the order that - * they complete. Delegate futures return the same value or throw the same exception as the - * corresponding input future returns/throws. - * - *

"In the order that they complete" means, for practical purposes, about what you would - * expect, but there are some subtleties. First, we do guarantee that, if the output future at - * index n is done, the output future at index n-1 is also done. (But as usual with futures, some - * listeners for future n may complete before some for future n-1.) However, it is possible, if - * one input completes with result X and another later with result Y, for Y to come before X in - * the output future list. (Such races are impossible to solve without global synchronization of - * all future completions. And they should have little practical impact.) - * - *

Cancelling a delegate future propagates to input futures once all the delegates complete, - * either from cancellation or because an input future has completed. If N futures are passed in, - * and M delegates are cancelled, the remaining M input futures will be cancelled once N - M of - * the input futures complete. If all the delegates are cancelled, all the input futures will be - * too. - * - * @since 17.0 - */ - public static ImmutableList> inCompletionOrder( - Iterable> futures) { - ListenableFuture[] copy = gwtCompatibleToArray(futures); - final InCompletionOrderState state = new InCompletionOrderState<>(copy); - ImmutableList.Builder> delegatesBuilder = - ImmutableList.builderWithExpectedSize(copy.length); - for (int i = 0; i < copy.length; i++) { - delegatesBuilder.add(new InCompletionOrderFuture(state)); - } - - final ImmutableList> delegates = delegatesBuilder.build(); - for (int i = 0; i < copy.length; i++) { - final int localI = i; - copy[i].addListener( - new Runnable() { - @Override - public void run() { - state.recordInputCompletion(delegates, localI); - } - }, - directExecutor()); - } - - @SuppressWarnings("unchecked") - ImmutableList> delegatesCast = (ImmutableList) delegates; - return delegatesCast; - } - - /** Can't use Iterables.toArray because it's not gwt compatible */ - @SuppressWarnings("unchecked") - private static ListenableFuture[] gwtCompatibleToArray( - Iterable> futures) { - final Collection> collection; - if (futures instanceof Collection) { - collection = (Collection>) futures; - } else { - collection = ImmutableList.copyOf(futures); - } - return (ListenableFuture[]) collection.toArray(new ListenableFuture[0]); - } - - // This can't be a TrustedFuture, because TrustedFuture has clever optimizations that - // mean cancel won't be called if this Future is passed into setFuture, and then - // cancelled. - private static final class InCompletionOrderFuture - extends AbstractFuture { - @CheckForNull private InCompletionOrderState state; - - private InCompletionOrderFuture(InCompletionOrderState state) { - this.state = state; - } - - @Override - public boolean cancel(boolean interruptIfRunning) { - InCompletionOrderState localState = state; - if (super.cancel(interruptIfRunning)) { - /* - * requireNonNull is generally safe: If cancel succeeded, then this Future was still - * pending, so its `state` field hasn't been nulled out yet. - * - * OK, it's technically possible for this to fail in the presence of unsafe publishing, as - * discussed in the comments in TimeoutFuture. TODO(cpovirk): Maybe check for null before - * calling recordOutputCancellation? - */ - requireNonNull(localState).recordOutputCancellation(interruptIfRunning); - return true; - } - return false; - } - - @Override - protected void afterDone() { - state = null; - } - - @Override - @CheckForNull - protected String pendingToString() { - InCompletionOrderState localState = state; - if (localState != null) { - // Don't print the actual array! We don't want inCompletionOrder(list).toString() to have - // quadratic output. - return "inputCount=[" - + localState.inputFutures.length - + "], remaining=[" - + localState.incompleteOutputCount.get() - + "]"; - } - return null; - } - } - - private static final class InCompletionOrderState { - // A happens-before edge between the writes of these fields and their reads exists, because - // in order to read these fields, the corresponding write to incompleteOutputCount must have - // been read. - private boolean wasCancelled = false; - private boolean shouldInterrupt = true; - private final AtomicInteger incompleteOutputCount; - // We set the elements of the array to null as they complete. - private final @Nullable ListenableFuture[] inputFutures; - private volatile int delegateIndex = 0; - - private InCompletionOrderState(ListenableFuture[] inputFutures) { - this.inputFutures = inputFutures; - incompleteOutputCount = new AtomicInteger(inputFutures.length); - } - - private void recordOutputCancellation(boolean interruptIfRunning) { - wasCancelled = true; - // If all the futures were cancelled with interruption, cancel the input futures - // with interruption; otherwise cancel without - if (!interruptIfRunning) { - shouldInterrupt = false; - } - recordCompletion(); - } - - private void recordInputCompletion( - ImmutableList> delegates, int inputFutureIndex) { - /* - * requireNonNull is safe because we accepted an Iterable of non-null Future instances, and we - * don't overwrite an element in the array until after reading it. - */ - ListenableFuture inputFuture = requireNonNull(inputFutures[inputFutureIndex]); - // Null out our reference to this future, so it can be GCed - inputFutures[inputFutureIndex] = null; - for (int i = delegateIndex; i < delegates.size(); i++) { - if (delegates.get(i).setFuture(inputFuture)) { - recordCompletion(); - // this is technically unnecessary, but should speed up later accesses - delegateIndex = i + 1; - return; - } - } - // If all the delegates were complete, no reason for the next listener to have to - // go through the whole list. Avoids O(n^2) behavior when the entire output list is - // cancelled. - delegateIndex = delegates.size(); - } - - private void recordCompletion() { - if (incompleteOutputCount.decrementAndGet() == 0 && wasCancelled) { - for (ListenableFuture toCancel : inputFutures) { - if (toCancel != null) { - toCancel.cancel(shouldInterrupt); - } - } - } - } - } - - /** - * Registers separate success and failure callbacks to be run when the {@code Future}'s - * computation is {@linkplain java.util.concurrent.Future#isDone() complete} or, if the - * computation is already complete, immediately. - * - *

The callback is run on {@code executor}. There is no guaranteed ordering of execution of - * callbacks, but any callback added through this method is guaranteed to be called once the - * computation is complete. - * - *

Exceptions thrown by a {@code callback} will be propagated up to the executor. Any exception - * thrown during {@code Executor.execute} (e.g., a {@code RejectedExecutionException} or an - * exception thrown by {@linkplain MoreExecutors#directExecutor direct execution}) will be caught - * and logged. - * - *

Example: - * - *

{@code
-   * ListenableFuture future = ...;
-   * Executor e = ...
-   * addCallback(future,
-   *     new FutureCallback() {
-   *       public void onSuccess(QueryResult result) {
-   *         storeInCache(result);
-   *       }
-   *       public void onFailure(Throwable t) {
-   *         reportError(t);
-   *       }
-   *     }, e);
-   * }
- * - *

When selecting an executor, note that {@code directExecutor} is dangerous in some cases. See - * the warnings the {@link MoreExecutors#directExecutor} documentation. - * - *

For a more general interface to attach a completion listener to a {@code Future}, see {@link - * ListenableFuture#addListener addListener}. - * - * @param future The future attach the callback to. - * @param callback The callback to invoke when {@code future} is completed. - * @param executor The executor to run {@code callback} when the future completes. - * @since 10.0 - */ - public static void addCallback( - final ListenableFuture future, - final FutureCallback callback, - Executor executor) { - Preconditions.checkNotNull(callback); - future.addListener(new CallbackListener(future, callback), executor); - } - - /** See {@link #addCallback(ListenableFuture, FutureCallback, Executor)} for behavioral notes. */ - private static final class CallbackListener implements Runnable { - final Future future; - final FutureCallback callback; - - CallbackListener(Future future, FutureCallback callback) { - this.future = future; - this.callback = callback; - } - - @Override - public void run() { - if (future instanceof InternalFutureFailureAccess) { - Throwable failure = - InternalFutures.tryInternalFastPathGetFailure((InternalFutureFailureAccess) future); - if (failure != null) { - callback.onFailure(failure); - return; - } - } - final V value; - try { - value = getDone(future); - } catch (ExecutionException e) { - callback.onFailure(e.getCause()); - return; - } catch (RuntimeException | Error e) { - callback.onFailure(e); - return; - } - callback.onSuccess(value); - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(this).addValue(callback).toString(); - } - } - - /** - * Returns the result of the input {@code Future}, which must have already completed. - * - *

The benefits of this method are twofold. First, the name "getDone" suggests to readers that - * the {@code Future} is already done. Second, if buggy code calls {@code getDone} on a {@code - * Future} that is still pending, the program will throw instead of block. This can be important - * for APIs like {@link #whenAllComplete whenAllComplete(...)}{@code .}{@link - * FutureCombiner#call(Callable, Executor) call(...)}, where it is easy to use a new input from - * the {@code call} implementation but forget to add it to the arguments of {@code - * whenAllComplete}. - * - *

If you are looking for a method to determine whether a given {@code Future} is done, use the - * instance method {@link Future#isDone()}. - * - * @throws ExecutionException if the {@code Future} failed with an exception - * @throws CancellationException if the {@code Future} was cancelled - * @throws IllegalStateException if the {@code Future} is not done - * @since 20.0 - */ - @CanIgnoreReturnValue - // TODO(cpovirk): Consider calling getDone() in our own code. - @ParametricNullness - public static V getDone(Future future) throws ExecutionException { - /* - * We throw IllegalStateException, since the call could succeed later. Perhaps we "should" throw - * IllegalArgumentException, since the call could succeed with a different argument. Those - * exceptions' docs suggest that either is acceptable. Google's Java Practices page recommends - * IllegalArgumentException here, in part to keep its recommendation simple: Static methods - * should throw IllegalStateException only when they use static state. - * - * Why do we deviate here? The answer: We want for fluentFuture.getDone() to throw the same - * exception as Futures.getDone(fluentFuture). - */ - checkState(future.isDone(), "Future was expected to be done: %s", future); - return getUninterruptibly(future); - } - - /** - * Returns the result of {@link Future#get()}, converting most exceptions to a new instance of the - * given checked exception type. This reduces boilerplate for a common use of {@code Future} in - * which it is unnecessary to programmatically distinguish between exception types or to extract - * other information from the exception instance. - * - *

Exceptions from {@code Future.get} are treated as follows: - * - *

    - *
  • Any {@link ExecutionException} has its cause wrapped in an {@code X} if the cause - * is a checked exception, an {@link UncheckedExecutionException} if the cause is a {@code - * RuntimeException}, or an {@link ExecutionError} if the cause is an {@code Error}. - *
  • Any {@link InterruptedException} is wrapped in an {@code X} (after restoring the - * interrupt). - *
  • Any {@link CancellationException} is propagated untouched, as is any other {@link - * RuntimeException} (though {@code get} implementations are discouraged from throwing such - * exceptions). - *
- * - *

The overall principle is to continue to treat every checked exception as a checked - * exception, every unchecked exception as an unchecked exception, and every error as an error. In - * addition, the cause of any {@code ExecutionException} is wrapped in order to ensure that the - * new stack trace matches that of the current thread. - * - *

Instances of {@code exceptionClass} are created by choosing an arbitrary public constructor - * that accepts zero or more arguments, all of type {@code String} or {@code Throwable} - * (preferring constructors with at least one {@code String}) and calling the constructor via - * reflection. If the exception did not already have a cause, one is set by calling {@link - * Throwable#initCause(Throwable)} on it. If no such constructor exists, an {@code - * IllegalArgumentException} is thrown. - * - * @throws X if {@code get} throws any checked exception except for an {@code ExecutionException} - * whose cause is not itself a checked exception - * @throws UncheckedExecutionException if {@code get} throws an {@code ExecutionException} with a - * {@code RuntimeException} as its cause - * @throws ExecutionError if {@code get} throws an {@code ExecutionException} with an {@code - * Error} as its cause - * @throws CancellationException if {@code get} throws a {@code CancellationException} - * @throws IllegalArgumentException if {@code exceptionClass} extends {@code RuntimeException} or - * does not have a suitable constructor - * @since 19.0 (in 10.0 as {@code get}) - */ - @Beta - @CanIgnoreReturnValue - @GwtIncompatible // reflection - @ParametricNullness - public static V getChecked( - Future future, Class exceptionClass) throws X { - return FuturesGetChecked.getChecked(future, exceptionClass); - } - - /** - * Returns the result of {@link Future#get(long, TimeUnit)}, converting most exceptions to a new - * instance of the given checked exception type. This reduces boilerplate for a common use of - * {@code Future} in which it is unnecessary to programmatically distinguish between exception - * types or to extract other information from the exception instance. - * - *

Exceptions from {@code Future.get} are treated as follows: - * - *

    - *
  • Any {@link ExecutionException} has its cause wrapped in an {@code X} if the cause - * is a checked exception, an {@link UncheckedExecutionException} if the cause is a {@code - * RuntimeException}, or an {@link ExecutionError} if the cause is an {@code Error}. - *
  • Any {@link InterruptedException} is wrapped in an {@code X} (after restoring the - * interrupt). - *
  • Any {@link TimeoutException} is wrapped in an {@code X}. - *
  • Any {@link CancellationException} is propagated untouched, as is any other {@link - * RuntimeException} (though {@code get} implementations are discouraged from throwing such - * exceptions). - *
- * - *

The overall principle is to continue to treat every checked exception as a checked - * exception, every unchecked exception as an unchecked exception, and every error as an error. In - * addition, the cause of any {@code ExecutionException} is wrapped in order to ensure that the - * new stack trace matches that of the current thread. - * - *

Instances of {@code exceptionClass} are created by choosing an arbitrary public constructor - * that accepts zero or more arguments, all of type {@code String} or {@code Throwable} - * (preferring constructors with at least one {@code String}) and calling the constructor via - * reflection. If the exception did not already have a cause, one is set by calling {@link - * Throwable#initCause(Throwable)} on it. If no such constructor exists, an {@code - * IllegalArgumentException} is thrown. - * - * @throws X if {@code get} throws any checked exception except for an {@code ExecutionException} - * whose cause is not itself a checked exception - * @throws UncheckedExecutionException if {@code get} throws an {@code ExecutionException} with a - * {@code RuntimeException} as its cause - * @throws ExecutionError if {@code get} throws an {@code ExecutionException} with an {@code - * Error} as its cause - * @throws CancellationException if {@code get} throws a {@code CancellationException} - * @throws IllegalArgumentException if {@code exceptionClass} extends {@code RuntimeException} or - * does not have a suitable constructor - * @since 28.0 - */ - @Beta - @CanIgnoreReturnValue - @GwtIncompatible // reflection - @ParametricNullness - public static V getChecked( - Future future, Class exceptionClass, Duration timeout) throws X { - return getChecked(future, exceptionClass, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); - } - - /** - * Returns the result of {@link Future#get(long, TimeUnit)}, converting most exceptions to a new - * instance of the given checked exception type. This reduces boilerplate for a common use of - * {@code Future} in which it is unnecessary to programmatically distinguish between exception - * types or to extract other information from the exception instance. - * - *

Exceptions from {@code Future.get} are treated as follows: - * - *

    - *
  • Any {@link ExecutionException} has its cause wrapped in an {@code X} if the cause - * is a checked exception, an {@link UncheckedExecutionException} if the cause is a {@code - * RuntimeException}, or an {@link ExecutionError} if the cause is an {@code Error}. - *
  • Any {@link InterruptedException} is wrapped in an {@code X} (after restoring the - * interrupt). - *
  • Any {@link TimeoutException} is wrapped in an {@code X}. - *
  • Any {@link CancellationException} is propagated untouched, as is any other {@link - * RuntimeException} (though {@code get} implementations are discouraged from throwing such - * exceptions). - *
- * - *

The overall principle is to continue to treat every checked exception as a checked - * exception, every unchecked exception as an unchecked exception, and every error as an error. In - * addition, the cause of any {@code ExecutionException} is wrapped in order to ensure that the - * new stack trace matches that of the current thread. - * - *

Instances of {@code exceptionClass} are created by choosing an arbitrary public constructor - * that accepts zero or more arguments, all of type {@code String} or {@code Throwable} - * (preferring constructors with at least one {@code String}) and calling the constructor via - * reflection. If the exception did not already have a cause, one is set by calling {@link - * Throwable#initCause(Throwable)} on it. If no such constructor exists, an {@code - * IllegalArgumentException} is thrown. - * - * @throws X if {@code get} throws any checked exception except for an {@code ExecutionException} - * whose cause is not itself a checked exception - * @throws UncheckedExecutionException if {@code get} throws an {@code ExecutionException} with a - * {@code RuntimeException} as its cause - * @throws ExecutionError if {@code get} throws an {@code ExecutionException} with an {@code - * Error} as its cause - * @throws CancellationException if {@code get} throws a {@code CancellationException} - * @throws IllegalArgumentException if {@code exceptionClass} extends {@code RuntimeException} or - * does not have a suitable constructor - * @since 19.0 (in 10.0 as {@code get} and with different parameter order) - */ - @Beta - @CanIgnoreReturnValue - @GwtIncompatible // reflection - @SuppressWarnings("GoodTime") // should accept a java.time.Duration - @ParametricNullness - public static V getChecked( - Future future, Class exceptionClass, long timeout, TimeUnit unit) throws X { - return FuturesGetChecked.getChecked(future, exceptionClass, timeout, unit); - } - - /** - * Returns the result of calling {@link Future#get()} uninterruptibly on a task known not to throw - * a checked exception. This makes {@code Future} more suitable for lightweight, fast-running - * tasks that, barring bugs in the code, will not fail. This gives it exception-handling behavior - * similar to that of {@code ForkJoinTask.join}. - * - *

Exceptions from {@code Future.get} are treated as follows: - * - *

    - *
  • Any {@link ExecutionException} has its cause wrapped in an {@link - * UncheckedExecutionException} (if the cause is an {@code Exception}) or {@link - * ExecutionError} (if the cause is an {@code Error}). - *
  • Any {@link InterruptedException} causes a retry of the {@code get} call. The interrupt is - * restored before {@code getUnchecked} returns. - *
  • Any {@link CancellationException} is propagated untouched. So is any other {@link - * RuntimeException} ({@code get} implementations are discouraged from throwing such - * exceptions). - *
- * - *

The overall principle is to eliminate all checked exceptions: to loop to avoid {@code - * InterruptedException}, to pass through {@code CancellationException}, and to wrap any exception - * from the underlying computation in an {@code UncheckedExecutionException} or {@code - * ExecutionError}. - * - *

For an uninterruptible {@code get} that preserves other exceptions, see {@link - * Uninterruptibles#getUninterruptibly(Future)}. - * - * @throws UncheckedExecutionException if {@code get} throws an {@code ExecutionException} with an - * {@code Exception} as its cause - * @throws ExecutionError if {@code get} throws an {@code ExecutionException} with an {@code - * Error} as its cause - * @throws CancellationException if {@code get} throws a {@code CancellationException} - * @since 10.0 - */ - @CanIgnoreReturnValue - @ParametricNullness - public static V getUnchecked(Future future) { - checkNotNull(future); - try { - return getUninterruptibly(future); - } catch (ExecutionException e) { - wrapAndThrowUnchecked(e.getCause()); - throw new AssertionError(); - } - } - - private static void wrapAndThrowUnchecked(Throwable cause) { - if (cause instanceof Error) { - throw new ExecutionError((Error) cause); - } - /* - * It's an Exception. (Or it's a non-Error, non-Exception Throwable. From my survey of such - * classes, I believe that most users intended to extend Exception, so we'll treat it like an - * Exception.) - */ - throw new UncheckedExecutionException(cause); - } - - /* - * Arguably we don't need a timed getUnchecked because any operation slow enough to require a - * timeout is heavyweight enough to throw a checked exception and therefore be inappropriate to - * use with getUnchecked. Further, it's not clear that converting the checked TimeoutException to - * a RuntimeException -- especially to an UncheckedExecutionException, since it wasn't thrown by - * the computation -- makes sense, and if we don't convert it, the user still has to write a - * try-catch block. - * - * If you think you would use this method, let us know. You might also look into the - * Fork-Join framework: http://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html - */ - - // Nacho start - /** - * Registers separate success and failure callbacks to be run when the {@code Future}'s - * computation is {@linkplain java.util.concurrent.Future#isDone() complete} or, if the - * computation is already complete, immediately. - * - *

There is no guaranteed ordering of execution of callbacks, but any callback added through - * this method is guaranteed to be called once the computation is complete. - * - *

Example: - * - *

{@code
-   * ListenableFuture future = ...;
-   * addCallback(future,
-   *     new FutureCallback() {
-   *       public void onSuccess(QueryResult result) {
-   *         storeInCache(result);
-   *       }
-   *       public void onFailure(Throwable t) {
-   *         reportError(t);
-   *       }
-   *     });
-   * }
- * - *

This overload, which does not accept an executor, uses {@code directExecutor}, a dangerous - * choice in some cases. See the discussion in the {@link ListenableFuture#addListener - * ListenableFuture.addListener} documentation. All its warnings about heavyweight listeners are - * also applicable to heavyweight callbacks passed to this method. - * - *

For a more general interface to attach a completion listener to a {@code Future}, see {@link - * ListenableFuture#addListener addListener}. - * - * @param future The future attach the callback to. - * @param callback The callback to invoke when {@code future} is completed. - * @since 10.0 - * @deprecated Use {@linkplain #addCallback(ListenableFuture, FutureCallback, Executor) the - * overload that requires an executor}. For identical behavior, pass {@link - * MoreExecutors#directExecutor}, but consider whether another executor would be safer, as - * discussed in the {@link ListenableFuture#addListener ListenableFuture.addListener} - * documentation. This method is scheduled to be removed in July 2018. - */ - @Deprecated - @com.google.errorprone.annotations.DoNotCall - public static void addCallback( - ListenableFuture future, FutureCallback callback) { - addCallback(future, callback, directExecutor()); - } - - /** - * Returns a new {@code Future} whose result is derived from the result of the given {@code - * Future}. If {@code input} fails, the returned {@code Future} fails with the same exception (and - * the function is not invoked). Example usage: - * - *

{@code
-   * ListenableFuture queryFuture = ...;
-   * ListenableFuture> rowsFuture =
-   *     transform(queryFuture, QueryResult::getRows);
-   * }
- * - *

This overload, which does not accept an executor, uses {@code directExecutor}, a dangerous - * choice in some cases. See the discussion in the {@link ListenableFuture#addListener - * ListenableFuture.addListener} documentation. All its warnings about heavyweight listeners are - * also applicable to heavyweight functions passed to this method. - * - *

The returned {@code Future} attempts to keep its cancellation state in sync with that of the - * input future. That is, if the returned {@code Future} is cancelled, it will attempt to cancel - * the input, and if the input is cancelled, the returned {@code Future} will receive a callback - * in which it will attempt to cancel itself. - * - *

An example use of this method is to convert a serializable object returned from an RPC into - * a POJO. - * - * @param input The future to transform - * @param function A Function to transform the results of the provided future to the results of - * the returned future. This will be run in the thread that notifies input it is complete. - * @return A future that holds result of the transformation. - * @since 9.0 (in 1.0 as {@code compose}) - * @deprecated Use {@linkplain #transform(ListenableFuture, Function, Executor) the overload that - * requires an executor}. For identical behavior, pass {@link MoreExecutors#directExecutor}, - * but consider whether another executor would be safer, as discussed in the {@link - * ListenableFuture#addListener ListenableFuture.addListener} documentation. This method is - * scheduled to be removed in July 2018. - */ - @Deprecated - @com.google.errorprone.annotations.DoNotCall - public static ListenableFuture transform( - ListenableFuture input, Function function) { - return AbstractTransformFuture.create(input, function, directExecutor()); - } - - /** - * Returns a new {@code Future} whose result is asynchronously derived from the result of the - * given {@code Future}. If the given {@code Future} fails, the returned {@code Future} fails with - * the same exception (and the function is not invoked). - * - *

More precisely, the returned {@code Future} takes its result from a {@code Future} produced - * by applying the given {@code AsyncFunction} to the result of the original {@code Future}. - * Example usage: - * - *

{@code
-   * ListenableFuture rowKeyFuture = indexService.lookUp(query);
-   * ListenableFuture queryFuture =
-   *     transformAsync(rowKeyFuture, dataService::readFuture);
-   * }
- * - *

This overload, which does not accept an executor, uses {@code directExecutor}, a dangerous - * choice in some cases. See the discussion in the {@link ListenableFuture#addListener - * ListenableFuture.addListener} documentation. All its warnings about heavyweight listeners are - * also applicable to heavyweight functions passed to this method. (Specifically, {@code - * directExecutor} functions should avoid heavyweight operations inside {@code - * AsyncFunction.apply}. Any heavyweight operations should occur in other threads responsible for - * completing the returned {@code Future}.) - * - *

The returned {@code Future} attempts to keep its cancellation state in sync with that of the - * input future and that of the future returned by the function. That is, if the returned {@code - * Future} is cancelled, it will attempt to cancel the other two, and if either of the other two - * is cancelled, the returned {@code Future} will receive a callback in which it will attempt to - * cancel itself. - * - * @param input The future to transform - * @param function A function to transform the result of the input future to the result of the - * output future - * @return A future that holds result of the function (if the input succeeded) or the original - * input's failure (if not) - * @since 19.0 (in 11.0 as {@code transform}) - * @deprecated Use {@linkplain #transformAsync(ListenableFuture, AsyncFunction, Executor) the - * overload that requires an executor}. For identical behavior, pass {@link - * MoreExecutors#directExecutor}, but consider whether another executor would be safer, as - * discussed in the {@link ListenableFuture#addListener ListenableFuture.addListener} - * documentation. This method is scheduled to be removed in July 2018. - */ - @Deprecated - @com.google.errorprone.annotations.DoNotCall - public static ListenableFuture transformAsync( - ListenableFuture input, AsyncFunction function) { - return AbstractTransformFuture.create(input, function, directExecutor()); - } - - /** - * Returns a {@code Future} whose result is taken from the given primary {@code input} or, if the - * primary input fails with the given {@code exceptionType}, from the result provided by the - * {@code fallback}. {@link Function#apply} is not invoked until the primary input has failed, so - * if the primary input succeeds, it is never invoked. If, during the invocation of {@code - * fallback}, an exception is thrown, this exception is used as the result of the output {@code - * Future}. - * - *

Usage example: - * - *

{@code
-   * ListenableFuture fetchCounterFuture = ...;
-   *
-   * // Falling back to a zero counter in case an exception happens when
-   * // processing the RPC to fetch counters.
-   * ListenableFuture faultTolerantFuture = Futures.catching(
-   *     fetchCounterFuture, FetchException.class, x -> 0);
-   * }
- * - *

This overload, which does not accept an executor, uses {@code directExecutor}, a dangerous - * choice in some cases. See the discussion in the {@link ListenableFuture#addListener - * ListenableFuture.addListener} documentation. All its warnings about heavyweight listeners are - * also applicable to heavyweight functions passed to this method. - * - * @param input the primary input {@code Future} - * @param exceptionType the exception type that triggers use of {@code fallback}. The exception - * type is matched against the input's exception. "The input's exception" means the cause of - * the {@link ExecutionException} thrown by {@code input.get()} or, if {@code get()} throws a - * different kind of exception, that exception itself. To avoid hiding bugs and other - * unrecoverable errors, callers should prefer more specific types, avoiding {@code - * Throwable.class} in particular. - * @param fallback the {@link Function} to be called if {@code input} fails with the expected - * exception type. The function's argument is the input's exception. "The input's exception" - * means the cause of the {@link ExecutionException} thrown by {@code input.get()} or, if - * {@code get()} throws a different kind of exception, that exception itself. - * @since 19.0 - * @deprecated Use {@linkplain #catching(ListenableFuture, Class, Function, Executor) the overload - * that requires an executor}. For identical behavior, pass {@link - * MoreExecutors#directExecutor}, but consider whether another executor would be safer, as - * discussed in the {@link ListenableFuture#addListener ListenableFuture.addListener} - * documentation. This method is scheduled to be removed in July 2018. - */ - @Deprecated - @com.google.errorprone.annotations.DoNotCall - @Partially.GwtIncompatible("AVAILABLE but requires exceptionType to be Throwable.class") - public static ListenableFuture catching( - ListenableFuture input, - Class exceptionType, - Function fallback) { - return AbstractCatchingFuture.create(input, exceptionType, fallback, directExecutor()); - } - - /** - * Returns a {@code Future} whose result is taken from the given primary {@code input} or, if the - * primary input fails with the given {@code exceptionType}, from the result provided by the - * {@code fallback}. {@link AsyncFunction#apply} is not invoked until the primary input has - * failed, so if the primary input succeeds, it is never invoked. If, during the invocation of - * {@code fallback}, an exception is thrown, this exception is used as the result of the output - * {@code Future}. - * - *

Usage examples: - * - *

{@code
-   * ListenableFuture fetchCounterFuture = ...;
-   *
-   * // Falling back to a zero counter in case an exception happens when
-   * // processing the RPC to fetch counters.
-   * ListenableFuture faultTolerantFuture = Futures.catchingAsync(
-   *     fetchCounterFuture, FetchException.class, x -> immediateFuture(0));
-   * }
- * - *

The fallback can also choose to propagate the original exception when desired: - * - *

{@code
-   * ListenableFuture fetchCounterFuture = ...;
-   *
-   * // Falling back to a zero counter only in case the exception was a
-   * // TimeoutException.
-   * ListenableFuture faultTolerantFuture = Futures.catchingAsync(
-   *     fetchCounterFuture,
-   *     FetchException.class,
-   *     e -> {
-   *       if (omitDataOnFetchFailure) {
-   *         return immediateFuture(0);
-   *       }
-   *       throw e;
-   *     });
-   * }
- * - *

This overload, which does not accept an executor, uses {@code directExecutor}, a dangerous - * choice in some cases. See the discussion in the {@link ListenableFuture#addListener - * ListenableFuture.addListener} documentation. All its warnings about heavyweight listeners are - * also applicable to heavyweight functions passed to this method. (Specifically, {@code - * directExecutor} functions should avoid heavyweight operations inside {@code - * AsyncFunction.apply}. Any heavyweight operations should occur in other threads responsible for - * completing the returned {@code Future}.) - * - * @param input the primary input {@code Future} - * @param exceptionType the exception type that triggers use of {@code fallback}. The exception - * type is matched against the input's exception. "The input's exception" means the cause of - * the {@link ExecutionException} thrown by {@code input.get()} or, if {@code get()} throws a - * different kind of exception, that exception itself. To avoid hiding bugs and other - * unrecoverable errors, callers should prefer more specific types, avoiding {@code - * Throwable.class} in particular. - * @param fallback the {@link AsyncFunction} to be called if {@code input} fails with the expected - * exception type. The function's argument is the input's exception. "The input's exception" - * means the cause of the {@link ExecutionException} thrown by {@code input.get()} or, if - * {@code get()} throws a different kind of exception, that exception itself. - * @since 19.0 (similar functionality in 14.0 as {@code withFallback}) - * @deprecated Use {@linkplain #catchingAsync(ListenableFuture, Class, AsyncFunction, Executor) - * the overload that requires an executor}. For identical behavior, pass {@link - * MoreExecutors#directExecutor}, but consider whether another executor would be safer, as - * discussed in the {@link ListenableFuture#addListener ListenableFuture.addListener} - * documentation. This method is scheduled to be removed in July 2018. - */ - @CanIgnoreReturnValue - @Deprecated - @com.google.errorprone.annotations.DoNotCall - @Partially.GwtIncompatible("AVAILABLE but requires exceptionType to be Throwable.class") - public static ListenableFuture catchingAsync( - ListenableFuture input, - Class exceptionType, - AsyncFunction fallback) { - return AbstractCatchingFuture.create(input, exceptionType, fallback, directExecutor()); - } - // Nacho end -} diff --git a/NachoSpigot-API/src/main/java/com/google/common/util/concurrent/MoreExecutors.java b/NachoSpigot-API/src/main/java/com/google/common/util/concurrent/MoreExecutors.java deleted file mode 100644 index 24b84d3c7..000000000 --- a/NachoSpigot-API/src/main/java/com/google/common/util/concurrent/MoreExecutors.java +++ /dev/null @@ -1,1172 +0,0 @@ -/* - * Copyright (C) 2007 The Guava Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.common.util.concurrent; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.util.concurrent.Internal.toNanosSaturated; - -import com.google.common.annotations.Beta; -import com.google.common.annotations.GwtCompatible; -import com.google.common.annotations.GwtIncompatible; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Supplier; -import com.google.common.base.Throwables; -import com.google.common.collect.Lists; -import com.google.common.collect.Queues; -import com.google.common.util.concurrent.ForwardingListenableFuture.SimpleForwardingListenableFuture; -import com.google.errorprone.annotations.CanIgnoreReturnValue; -import com.google.errorprone.annotations.concurrent.GuardedBy; -import java.lang.reflect.InvocationTargetException; -import java.time.Duration; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.Callable; -import java.util.concurrent.Delayed; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import org.checkerframework.checker.nullness.qual.Nullable; - -/** - * Factory and utility methods for {@link java.util.concurrent.Executor}, {@link ExecutorService}, - * and {@link java.util.concurrent.ThreadFactory}. - * - * @author Eric Fellheimer - * @author Kyle Littlefield - * @author Justin Mahoney - * @since 3.0 - */ -@GwtCompatible(emulated = true) -@ElementTypesAreNonnullByDefault -public final class MoreExecutors { - private MoreExecutors() {} - - /** - * Converts the given ThreadPoolExecutor into an ExecutorService that exits when the application - * is complete. It does so by using daemon threads and adding a shutdown hook to wait for their - * completion. - * - *

This is mainly for fixed thread pools. See {@link Executors#newFixedThreadPool(int)}. - * - * @param executor the executor to modify to make sure it exits when the application is finished - * @param terminationTimeout how long to wait for the executor to finish before terminating the - * JVM - * @return an unmodifiable version of the input which will not hang the JVM - * @since 28.0 - */ - @Beta - @GwtIncompatible // TODO - public static ExecutorService getExitingExecutorService( - ThreadPoolExecutor executor, Duration terminationTimeout) { - return getExitingExecutorService( - executor, toNanosSaturated(terminationTimeout), TimeUnit.NANOSECONDS); - } - - /** - * Converts the given ThreadPoolExecutor into an ExecutorService that exits when the application - * is complete. It does so by using daemon threads and adding a shutdown hook to wait for their - * completion. - * - *

This is mainly for fixed thread pools. See {@link Executors#newFixedThreadPool(int)}. - * - * @param executor the executor to modify to make sure it exits when the application is finished - * @param terminationTimeout how long to wait for the executor to finish before terminating the - * JVM - * @param timeUnit unit of time for the time parameter - * @return an unmodifiable version of the input which will not hang the JVM - */ - @Beta - @GwtIncompatible // TODO - @SuppressWarnings("GoodTime") // should accept a java.time.Duration - public static ExecutorService getExitingExecutorService( - ThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) { - return new Application().getExitingExecutorService(executor, terminationTimeout, timeUnit); - } - - /** - * Converts the given ThreadPoolExecutor into an ExecutorService that exits when the application - * is complete. It does so by using daemon threads and adding a shutdown hook to wait for their - * completion. - * - *

This method waits 120 seconds before continuing with JVM termination, even if the executor - * has not finished its work. - * - *

This is mainly for fixed thread pools. See {@link Executors#newFixedThreadPool(int)}. - * - * @param executor the executor to modify to make sure it exits when the application is finished - * @return an unmodifiable version of the input which will not hang the JVM - */ - @Beta - @GwtIncompatible // concurrency - public static ExecutorService getExitingExecutorService(ThreadPoolExecutor executor) { - return new Application().getExitingExecutorService(executor); - } - - /** - * Converts the given ScheduledThreadPoolExecutor into a ScheduledExecutorService that exits when - * the application is complete. It does so by using daemon threads and adding a shutdown hook to - * wait for their completion. - * - *

This is mainly for fixed thread pools. See {@link Executors#newScheduledThreadPool(int)}. - * - * @param executor the executor to modify to make sure it exits when the application is finished - * @param terminationTimeout how long to wait for the executor to finish before terminating the - * JVM - * @return an unmodifiable version of the input which will not hang the JVM - * @since 28.0 - */ - @Beta - @GwtIncompatible // java.time.Duration - public static ScheduledExecutorService getExitingScheduledExecutorService( - ScheduledThreadPoolExecutor executor, Duration terminationTimeout) { - return getExitingScheduledExecutorService( - executor, toNanosSaturated(terminationTimeout), TimeUnit.NANOSECONDS); - } - - /** - * Converts the given ScheduledThreadPoolExecutor into a ScheduledExecutorService that exits when - * the application is complete. It does so by using daemon threads and adding a shutdown hook to - * wait for their completion. - * - *

This is mainly for fixed thread pools. See {@link Executors#newScheduledThreadPool(int)}. - * - * @param executor the executor to modify to make sure it exits when the application is finished - * @param terminationTimeout how long to wait for the executor to finish before terminating the - * JVM - * @param timeUnit unit of time for the time parameter - * @return an unmodifiable version of the input which will not hang the JVM - */ - @Beta - @GwtIncompatible // TODO - @SuppressWarnings("GoodTime") // should accept a java.time.Duration - public static ScheduledExecutorService getExitingScheduledExecutorService( - ScheduledThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) { - return new Application() - .getExitingScheduledExecutorService(executor, terminationTimeout, timeUnit); - } - - /** - * Converts the given ScheduledThreadPoolExecutor into a ScheduledExecutorService that exits when - * the application is complete. It does so by using daemon threads and adding a shutdown hook to - * wait for their completion. - * - *

This method waits 120 seconds before continuing with JVM termination, even if the executor - * has not finished its work. - * - *

This is mainly for fixed thread pools. See {@link Executors#newScheduledThreadPool(int)}. - * - * @param executor the executor to modify to make sure it exits when the application is finished - * @return an unmodifiable version of the input which will not hang the JVM - */ - @Beta - @GwtIncompatible // TODO - public static ScheduledExecutorService getExitingScheduledExecutorService( - ScheduledThreadPoolExecutor executor) { - return new Application().getExitingScheduledExecutorService(executor); - } - - /** - * Add a shutdown hook to wait for thread completion in the given {@link ExecutorService service}. - * This is useful if the given service uses daemon threads, and we want to keep the JVM from - * exiting immediately on shutdown, instead giving these daemon threads a chance to terminate - * normally. - * - * @param service ExecutorService which uses daemon threads - * @param terminationTimeout how long to wait for the executor to finish before terminating the - * JVM - * @since 28.0 - */ - @Beta - @GwtIncompatible // java.time.Duration - public static void addDelayedShutdownHook(ExecutorService service, Duration terminationTimeout) { - addDelayedShutdownHook(service, toNanosSaturated(terminationTimeout), TimeUnit.NANOSECONDS); - } - - /** - * Add a shutdown hook to wait for thread completion in the given {@link ExecutorService service}. - * This is useful if the given service uses daemon threads, and we want to keep the JVM from - * exiting immediately on shutdown, instead giving these daemon threads a chance to terminate - * normally. - * - * @param service ExecutorService which uses daemon threads - * @param terminationTimeout how long to wait for the executor to finish before terminating the - * JVM - * @param timeUnit unit of time for the time parameter - */ - @Beta - @GwtIncompatible // TODO - @SuppressWarnings("GoodTime") // should accept a java.time.Duration - public static void addDelayedShutdownHook( - ExecutorService service, long terminationTimeout, TimeUnit timeUnit) { - new Application().addDelayedShutdownHook(service, terminationTimeout, timeUnit); - } - - /** Represents the current application to register shutdown hooks. */ - @GwtIncompatible // TODO - @VisibleForTesting - static class Application { - - final ExecutorService getExitingExecutorService( - ThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) { - useDaemonThreadFactory(executor); - ExecutorService service = Executors.unconfigurableExecutorService(executor); - addDelayedShutdownHook(executor, terminationTimeout, timeUnit); - return service; - } - - final ExecutorService getExitingExecutorService(ThreadPoolExecutor executor) { - return getExitingExecutorService(executor, 120, TimeUnit.SECONDS); - } - - final ScheduledExecutorService getExitingScheduledExecutorService( - ScheduledThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) { - useDaemonThreadFactory(executor); - ScheduledExecutorService service = Executors.unconfigurableScheduledExecutorService(executor); - addDelayedShutdownHook(executor, terminationTimeout, timeUnit); - return service; - } - - final ScheduledExecutorService getExitingScheduledExecutorService( - ScheduledThreadPoolExecutor executor) { - return getExitingScheduledExecutorService(executor, 120, TimeUnit.SECONDS); - } - - final void addDelayedShutdownHook( - final ExecutorService service, final long terminationTimeout, final TimeUnit timeUnit) { - checkNotNull(service); - checkNotNull(timeUnit); - addShutdownHook( - MoreExecutors.newThread( - "DelayedShutdownHook-for-" + service, - new Runnable() { - @Override - public void run() { - try { - // We'd like to log progress and failures that may arise in the - // following code, but unfortunately the behavior of logging - // is undefined in shutdown hooks. - // This is because the logging code installs a shutdown hook of its - // own. See Cleaner class inside {@link LogManager}. - service.shutdown(); - service.awaitTermination(terminationTimeout, timeUnit); - } catch (InterruptedException ignored) { - // We're shutting down anyway, so just ignore. - } - } - })); - } - - @VisibleForTesting - void addShutdownHook(Thread hook) { - Runtime.getRuntime().addShutdownHook(hook); - } - } - - @GwtIncompatible // TODO - private static void useDaemonThreadFactory(ThreadPoolExecutor executor) { - executor.setThreadFactory( - new ThreadFactoryBuilder() - .setDaemon(true) - .setThreadFactory(executor.getThreadFactory()) - .build()); - } - - // See newDirectExecutorService javadoc for behavioral notes. - @GwtIncompatible // TODO - private static final class DirectExecutorService extends AbstractListeningExecutorService { - /** Lock used whenever accessing the state variables (runningTasks, shutdown) of the executor */ - private final Object lock = new Object(); - - /* - * Conceptually, these two variables describe the executor being in - * one of three states: - * - Active: shutdown == false - * - Shutdown: runningTasks > 0 and shutdown == true - * - Terminated: runningTasks == 0 and shutdown == true - */ - @GuardedBy("lock") - private int runningTasks = 0; - - @GuardedBy("lock") - private boolean shutdown = false; - - @Override - public void execute(Runnable command) { - startTask(); - try { - command.run(); - } finally { - endTask(); - } - } - - @Override - public boolean isShutdown() { - synchronized (lock) { - return shutdown; - } - } - - @Override - public void shutdown() { - synchronized (lock) { - shutdown = true; - if (runningTasks == 0) { - lock.notifyAll(); - } - } - } - - // See newDirectExecutorService javadoc for unusual behavior of this method. - @Override - public List shutdownNow() { - shutdown(); - return Collections.emptyList(); - } - - @Override - public boolean isTerminated() { - synchronized (lock) { - return shutdown && runningTasks == 0; - } - } - - @Override - public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { - long nanos = unit.toNanos(timeout); - synchronized (lock) { - while (true) { - if (shutdown && runningTasks == 0) { - return true; - } else if (nanos <= 0) { - return false; - } else { - long now = System.nanoTime(); - TimeUnit.NANOSECONDS.timedWait(lock, nanos); - nanos -= System.nanoTime() - now; // subtract the actual time we waited - } - } - } - } - - /** - * Checks if the executor has been shut down and increments the running task count. - * - * @throws RejectedExecutionException if the executor has been previously shutdown - */ - private void startTask() { - synchronized (lock) { - if (shutdown) { - throw new RejectedExecutionException("Executor already shutdown"); - } - runningTasks++; - } - } - - /** Decrements the running task count. */ - private void endTask() { - synchronized (lock) { - int numRunning = --runningTasks; - if (numRunning == 0) { - lock.notifyAll(); - } - } - } - } - - /** - * Creates an executor service that runs each task in the thread that invokes {@code - * execute/submit}, as in {@code ThreadPoolExecutor.CallerRunsPolicy}. This applies both to - * individually submitted tasks and to collections of tasks submitted via {@code invokeAll} or - * {@code invokeAny}. In the latter case, tasks will run serially on the calling thread. Tasks are - * run to completion before a {@code Future} is returned to the caller (unless the executor has - * been shutdown). - * - *

Although all tasks are immediately executed in the thread that submitted the task, this - * {@code ExecutorService} imposes a small locking overhead on each task submission in order to - * implement shutdown and termination behavior. - * - *

The implementation deviates from the {@code ExecutorService} specification with regards to - * the {@code shutdownNow} method. First, "best-effort" with regards to canceling running tasks is - * implemented as "no-effort". No interrupts or other attempts are made to stop threads executing - * tasks. Second, the returned list will always be empty, as any submitted task is considered to - * have started execution. This applies also to tasks given to {@code invokeAll} or {@code - * invokeAny} which are pending serial execution, even the subset of the tasks that have not yet - * started execution. It is unclear from the {@code ExecutorService} specification if these should - * be included, and it's much easier to implement the interpretation that they not be. Finally, a - * call to {@code shutdown} or {@code shutdownNow} may result in concurrent calls to {@code - * invokeAll/invokeAny} throwing RejectedExecutionException, although a subset of the tasks may - * already have been executed. - * - * @since 18.0 (present as MoreExecutors.sameThreadExecutor() since 10.0) - */ - @GwtIncompatible // TODO - public static ListeningExecutorService newDirectExecutorService() { - return new DirectExecutorService(); - } - - /** - * Returns an {@link Executor} that runs each task in the thread that invokes {@link - * Executor#execute execute}, as in {@code ThreadPoolExecutor.CallerRunsPolicy}. - * - *

This executor is appropriate for tasks that are lightweight and not deeply chained. - * Inappropriate {@code directExecutor} usage can cause problems, and these problems can be - * difficult to reproduce because they depend on timing. For example: - * - *

    - *
  • A call like {@code future.transform(function, directExecutor())} may execute the function - * immediately in the thread that is calling {@code transform}. (This specific case happens - * if the future is already completed.) If {@code transform} call was made from a UI thread - * or other latency-sensitive thread, a heavyweight function can harm responsiveness. - *
  • If the task will be executed later, consider which thread will trigger the execution -- - * since that thread will execute the task inline. If the thread is a shared system thread - * like an RPC network thread, a heavyweight task can stall progress of the whole system or - * even deadlock it. - *
  • If many tasks will be triggered by the same event, one heavyweight task may delay other - * tasks -- even tasks that are not themselves {@code directExecutor} tasks. - *
  • If many such tasks are chained together (such as with {@code - * future.transform(...).transform(...).transform(...)....}), they may overflow the stack. - * (In simple cases, callers can avoid this by registering all tasks with the same {@link - * MoreExecutors#newSequentialExecutor} wrapper around {@code directExecutor()}. More - * complex cases may require using thread pools or making deeper changes.) - *
  • If an exception propagates out of a {@code Runnable}, it is not necessarily seen by any - * {@code UncaughtExceptionHandler} for the thread. For example, if the callback passed to - * {@link Futures#addCallback} throws an exception, that exception will be typically be - * logged by the {@link ListenableFuture} implementation, even if the thread is configured - * to do something different. In other cases, no code will catch the exception, and it may - * terminate whichever thread happens to trigger the execution. - *
- * - * Additionally, beware of executing tasks with {@code directExecutor} while holding a lock. Since - * the task you submit to the executor (or any other arbitrary work the executor does) may do slow - * work or acquire other locks, you risk deadlocks. - * - *

This instance is equivalent to: - * - *

{@code
-     * final class DirectExecutor implements Executor {
-     *   public void execute(Runnable r) {
-     *     r.run();
-     *   }
-     * }
-     * }
- * - *

This should be preferred to {@link #newDirectExecutorService()} because implementing the - * {@link ExecutorService} subinterface necessitates significant performance overhead. - * - * @since 18.0 - */ - public static Executor directExecutor() { - return DirectExecutor.INSTANCE; - } - - /** - * Returns an {@link Executor} that runs each task executed sequentially, such that no two tasks - * are running concurrently. Submitted tasks have a happens-before order as defined in the Java - * Language Specification. - * - *

The executor uses {@code delegate} in order to {@link Executor#execute execute} each task in - * turn, and does not create any threads of its own. - * - *

After execution begins on a thread from the {@code delegate} {@link Executor}, tasks are - * polled and executed from a task queue until there are no more tasks. The thread will not be - * released until there are no more tasks to run. - * - *

If a task is submitted while a thread is executing tasks from the task queue, the thread - * will not be released until that submitted task is also complete. - * - *

If a task is {@linkplain Thread#interrupt interrupted} while a task is running: - * - *

    - *
  1. execution will not stop until the task queue is empty. - *
  2. tasks will begin execution with the thread marked as not interrupted - any interruption - * applies only to the task that was running at the point of interruption. - *
  3. if the thread was interrupted before the SequentialExecutor's worker begins execution, - * the interrupt will be restored to the thread after it completes so that its {@code - * delegate} Executor may process the interrupt. - *
  4. subtasks are run with the thread uninterrupted and interrupts received during execution - * of a task are ignored. - *
- * - *

{@code RuntimeException}s thrown by tasks are simply logged and the executor keeps trucking. - * If an {@code Error} is thrown, the error will propagate and execution will stop until the next - * time a task is submitted. - * - *

When an {@code Error} is thrown by an executed task, previously submitted tasks may never - * run. An attempt will be made to restart execution on the next call to {@code execute}. If the - * {@code delegate} has begun to reject execution, the previously submitted tasks may never run, - * despite not throwing a RejectedExecutionException synchronously with the call to {@code - * execute}. If this behaviour is problematic, use an Executor with a single thread (e.g. {@link - * Executors#newSingleThreadExecutor}). - * - * @since 23.3 (since 23.1 as {@code sequentialExecutor}) - */ - @Beta - @GwtIncompatible - public static Executor newSequentialExecutor(Executor delegate) { - return new SequentialExecutor(delegate); - } - - /** - * Creates an {@link ExecutorService} whose {@code submit} and {@code invokeAll} methods submit - * {@link ListenableFutureTask} instances to the given delegate executor. Those methods, as well - * as {@code execute} and {@code invokeAny}, are implemented in terms of calls to {@code - * delegate.execute}. All other methods are forwarded unchanged to the delegate. This implies that - * the returned {@code ListeningExecutorService} never calls the delegate's {@code submit}, {@code - * invokeAll}, and {@code invokeAny} methods, so any special handling of tasks must be implemented - * in the delegate's {@code execute} method or by wrapping the returned {@code - * ListeningExecutorService}. - * - *

If the delegate executor was already an instance of {@code ListeningExecutorService}, it is - * returned untouched, and the rest of this documentation does not apply. - * - * @since 10.0 - */ - @GwtIncompatible // TODO - public static ListeningExecutorService listeningDecorator(ExecutorService delegate) { - return (delegate instanceof ListeningExecutorService) - ? (ListeningExecutorService) delegate - : (delegate instanceof ScheduledExecutorService) - ? new ScheduledListeningDecorator((ScheduledExecutorService) delegate) - : new ListeningDecorator(delegate); - } - - /** - * Creates a {@link ScheduledExecutorService} whose {@code submit} and {@code invokeAll} methods - * submit {@link ListenableFutureTask} instances to the given delegate executor. Those methods, as - * well as {@code execute} and {@code invokeAny}, are implemented in terms of calls to {@code - * delegate.execute}. All other methods are forwarded unchanged to the delegate. This implies that - * the returned {@code ListeningScheduledExecutorService} never calls the delegate's {@code - * submit}, {@code invokeAll}, and {@code invokeAny} methods, so any special handling of tasks - * must be implemented in the delegate's {@code execute} method or by wrapping the returned {@code - * ListeningScheduledExecutorService}. - * - *

If the delegate executor was already an instance of {@code - * ListeningScheduledExecutorService}, it is returned untouched, and the rest of this - * documentation does not apply. - * - * @since 10.0 - */ - @GwtIncompatible // TODO - public static ListeningScheduledExecutorService listeningDecorator( - ScheduledExecutorService delegate) { - return (delegate instanceof ListeningScheduledExecutorService) - ? (ListeningScheduledExecutorService) delegate - : new ScheduledListeningDecorator(delegate); - } - - @GwtIncompatible // TODO - private static class ListeningDecorator extends AbstractListeningExecutorService { - private final ExecutorService delegate; - - ListeningDecorator(ExecutorService delegate) { - this.delegate = checkNotNull(delegate); - } - - @Override - public final boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { - return delegate.awaitTermination(timeout, unit); - } - - @Override - public final boolean isShutdown() { - return delegate.isShutdown(); - } - - @Override - public final boolean isTerminated() { - return delegate.isTerminated(); - } - - @Override - public final void shutdown() { - delegate.shutdown(); - } - - @Override - public final List shutdownNow() { - return delegate.shutdownNow(); - } - - @Override - public final void execute(Runnable command) { - delegate.execute(command); - } - - @Override - public final String toString() { - return super.toString() + "[" + delegate + "]"; - } - } - - @GwtIncompatible // TODO - private static final class ScheduledListeningDecorator extends ListeningDecorator - implements ListeningScheduledExecutorService { - @SuppressWarnings("hiding") - final ScheduledExecutorService delegate; - - ScheduledListeningDecorator(ScheduledExecutorService delegate) { - super(delegate); - this.delegate = checkNotNull(delegate); - } - - @Override - public ListenableScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { - TrustedListenableFutureTask<@Nullable Void> task = - TrustedListenableFutureTask.create(command, null); - ScheduledFuture scheduled = delegate.schedule(task, delay, unit); - return new ListenableScheduledTask<@Nullable Void>(task, scheduled); - } - - @Override - public ListenableScheduledFuture schedule( - Callable callable, long delay, TimeUnit unit) { - TrustedListenableFutureTask task = TrustedListenableFutureTask.create(callable); - ScheduledFuture scheduled = delegate.schedule(task, delay, unit); - return new ListenableScheduledTask(task, scheduled); - } - - @Override - public ListenableScheduledFuture scheduleAtFixedRate( - Runnable command, long initialDelay, long period, TimeUnit unit) { - NeverSuccessfulListenableFutureTask task = new NeverSuccessfulListenableFutureTask(command); - ScheduledFuture scheduled = delegate.scheduleAtFixedRate(task, initialDelay, period, unit); - return new ListenableScheduledTask<@Nullable Void>(task, scheduled); - } - - @Override - public ListenableScheduledFuture scheduleWithFixedDelay( - Runnable command, long initialDelay, long delay, TimeUnit unit) { - NeverSuccessfulListenableFutureTask task = new NeverSuccessfulListenableFutureTask(command); - ScheduledFuture scheduled = - delegate.scheduleWithFixedDelay(task, initialDelay, delay, unit); - return new ListenableScheduledTask<@Nullable Void>(task, scheduled); - } - - private static final class ListenableScheduledTask - extends SimpleForwardingListenableFuture implements ListenableScheduledFuture { - - private final ScheduledFuture scheduledDelegate; - - public ListenableScheduledTask( - ListenableFuture listenableDelegate, ScheduledFuture scheduledDelegate) { - super(listenableDelegate); - this.scheduledDelegate = scheduledDelegate; - } - - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - boolean cancelled = super.cancel(mayInterruptIfRunning); - if (cancelled) { - // Unless it is cancelled, the delegate may continue being scheduled - scheduledDelegate.cancel(mayInterruptIfRunning); - - // TODO(user): Cancel "this" if "scheduledDelegate" is cancelled. - } - return cancelled; - } - - @Override - public long getDelay(TimeUnit unit) { - return scheduledDelegate.getDelay(unit); - } - - @Override - public int compareTo(Delayed other) { - return scheduledDelegate.compareTo(other); - } - } - - @GwtIncompatible // TODO - private static final class NeverSuccessfulListenableFutureTask - extends AbstractFuture.TrustedFuture<@Nullable Void> implements Runnable { - private final Runnable delegate; - - public NeverSuccessfulListenableFutureTask(Runnable delegate) { - this.delegate = checkNotNull(delegate); - } - - @Override - public void run() { - try { - delegate.run(); - } catch (Throwable t) { - setException(t); - throw Throwables.propagate(t); - } - } - - @Override - protected String pendingToString() { - return "task=[" + delegate + "]"; - } - } - } - - /* - * This following method is a modified version of one found in - * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/test/tck/AbstractExecutorServiceTest.java?revision=1.30 - * which contained the following notice: - * - * Written by Doug Lea with assistance from members of JCP JSR-166 Expert Group and released to - * the public domain, as explained at http://creativecommons.org/publicdomain/zero/1.0/ - * - * Other contributors include Andrew Wright, Jeffrey Hayes, Pat Fisher, Mike Judd. - */ - - /** - * An implementation of {@link ExecutorService#invokeAny} for {@link ListeningExecutorService} - * implementations. - */ - @GwtIncompatible - @ParametricNullness - static T invokeAnyImpl( - ListeningExecutorService executorService, - Collection> tasks, - boolean timed, - Duration timeout) - throws InterruptedException, ExecutionException, TimeoutException { - return invokeAnyImpl( - executorService, tasks, timed, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); - } - - /** - * An implementation of {@link ExecutorService#invokeAny} for {@link ListeningExecutorService} - * implementations. - */ - @SuppressWarnings("GoodTime") // should accept a java.time.Duration - @GwtIncompatible - @ParametricNullness - static T invokeAnyImpl( - ListeningExecutorService executorService, - Collection> tasks, - boolean timed, - long timeout, - TimeUnit unit) - throws InterruptedException, ExecutionException, TimeoutException { - checkNotNull(executorService); - checkNotNull(unit); - int ntasks = tasks.size(); - checkArgument(ntasks > 0); - List> futures = Lists.newArrayListWithCapacity(ntasks); - BlockingQueue> futureQueue = Queues.newLinkedBlockingQueue(); - long timeoutNanos = unit.toNanos(timeout); - - // For efficiency, especially in executors with limited - // parallelism, check to see if previously submitted tasks are - // done before submitting more of them. This interleaving - // plus the exception mechanics account for messiness of main - // loop. - - try { - // Record exceptions so that if we fail to obtain any - // result, we can throw the last exception we got. - ExecutionException ee = null; - long lastTime = timed ? System.nanoTime() : 0; - Iterator> it = tasks.iterator(); - - futures.add(submitAndAddQueueListener(executorService, it.next(), futureQueue)); - --ntasks; - int active = 1; - - while (true) { - Future f = futureQueue.poll(); - if (f == null) { - if (ntasks > 0) { - --ntasks; - futures.add(submitAndAddQueueListener(executorService, it.next(), futureQueue)); - ++active; - } else if (active == 0) { - break; - } else if (timed) { - f = futureQueue.poll(timeoutNanos, TimeUnit.NANOSECONDS); - if (f == null) { - throw new TimeoutException(); - } - long now = System.nanoTime(); - timeoutNanos -= now - lastTime; - lastTime = now; - } else { - f = futureQueue.take(); - } - } - if (f != null) { - --active; - try { - return f.get(); - } catch (ExecutionException eex) { - ee = eex; - } catch (RuntimeException rex) { - ee = new ExecutionException(rex); - } - } - } - - if (ee == null) { - ee = new ExecutionException(null); - } - throw ee; - } finally { - for (Future f : futures) { - f.cancel(true); - } - } - } - - /** - * Submits the task and adds a listener that adds the future to {@code queue} when it completes. - */ - @GwtIncompatible // TODO - private static ListenableFuture submitAndAddQueueListener( - ListeningExecutorService executorService, - Callable task, - final BlockingQueue> queue) { - final ListenableFuture future = executorService.submit(task); - future.addListener( - new Runnable() { - @Override - public void run() { - queue.add(future); - } - }, - directExecutor()); - return future; - } - - /** - * Returns a default thread factory used to create new threads. - * - *

When running on AppEngine with access to AppEngine legacy - * APIs, this method returns {@code ThreadManager.currentRequestThreadFactory()}. Otherwise, - * it returns {@link Executors#defaultThreadFactory()}. - * - * @since 14.0 - */ - @Beta - @GwtIncompatible // concurrency - public static ThreadFactory platformThreadFactory() { - if (!isAppEngineWithApiClasses()) { - return Executors.defaultThreadFactory(); - } - try { - return (ThreadFactory) - Class.forName("com.google.appengine.api.ThreadManager") - .getMethod("currentRequestThreadFactory") - .invoke(null); - /* - * Do not merge the 3 catch blocks below. javac would infer a type of - * ReflectiveOperationException, which Animal Sniffer would reject. (Old versions of Android - * don't *seem* to mind, but there might be edge cases of which we're unaware.) - */ - } catch (IllegalAccessException e) { - throw new RuntimeException("Couldn't invoke ThreadManager.currentRequestThreadFactory", e); - } catch (ClassNotFoundException e) { - throw new RuntimeException("Couldn't invoke ThreadManager.currentRequestThreadFactory", e); - } catch (NoSuchMethodException e) { - throw new RuntimeException("Couldn't invoke ThreadManager.currentRequestThreadFactory", e); - } catch (InvocationTargetException e) { - throw Throwables.propagate(e.getCause()); - } - } - - @GwtIncompatible // TODO - private static boolean isAppEngineWithApiClasses() { - if (System.getProperty("com.google.appengine.runtime.environment") == null) { - return false; - } - try { - Class.forName("com.google.appengine.api.utils.SystemProperty"); - } catch (ClassNotFoundException e) { - return false; - } - try { - // If the current environment is null, we're not inside AppEngine. - return Class.forName("com.google.apphosting.api.ApiProxy") - .getMethod("getCurrentEnvironment") - .invoke(null) - != null; - } catch (ClassNotFoundException e) { - // If ApiProxy doesn't exist, we're not on AppEngine at all. - return false; - } catch (InvocationTargetException e) { - // If ApiProxy throws an exception, we're not in a proper AppEngine environment. - return false; - } catch (IllegalAccessException e) { - // If the method isn't accessible, we're not on a supported version of AppEngine; - return false; - } catch (NoSuchMethodException e) { - // If the method doesn't exist, we're not on a supported version of AppEngine; - return false; - } - } - - /** - * Creates a thread using {@link #platformThreadFactory}, and sets its name to {@code name} unless - * changing the name is forbidden by the security manager. - */ - @GwtIncompatible // concurrency - static Thread newThread(String name, Runnable runnable) { - checkNotNull(name); - checkNotNull(runnable); - Thread result = platformThreadFactory().newThread(runnable); - try { - result.setName(name); - } catch (SecurityException e) { - // OK if we can't set the name in this environment. - } - return result; - } - - // TODO(lukes): provide overloads for ListeningExecutorService? ListeningScheduledExecutorService? - // TODO(lukes): provide overloads that take constant strings? Functions to - // calculate names? - - /** - * Creates an {@link Executor} that renames the {@link Thread threads} that its tasks run in. - * - *

The names are retrieved from the {@code nameSupplier} on the thread that is being renamed - * right before each task is run. The renaming is best effort, if a {@link SecurityManager} - * prevents the renaming then it will be skipped but the tasks will still execute. - * - * @param executor The executor to decorate - * @param nameSupplier The source of names for each task - */ - @GwtIncompatible // concurrency - static Executor renamingDecorator(final Executor executor, final Supplier nameSupplier) { - checkNotNull(executor); - checkNotNull(nameSupplier); - return new Executor() { - @Override - public void execute(Runnable command) { - executor.execute(Callables.threadRenaming(command, nameSupplier)); - } - }; - } - - /** - * Creates an {@link ExecutorService} that renames the {@link Thread threads} that its tasks run - * in. - * - *

The names are retrieved from the {@code nameSupplier} on the thread that is being renamed - * right before each task is run. The renaming is best effort, if a {@link SecurityManager} - * prevents the renaming then it will be skipped but the tasks will still execute. - * - * @param service The executor to decorate - * @param nameSupplier The source of names for each task - */ - @GwtIncompatible // concurrency - static ExecutorService renamingDecorator( - final ExecutorService service, final Supplier nameSupplier) { - checkNotNull(service); - checkNotNull(nameSupplier); - return new WrappingExecutorService(service) { - @Override - protected Callable wrapTask(Callable callable) { - return Callables.threadRenaming(callable, nameSupplier); - } - - @Override - protected Runnable wrapTask(Runnable command) { - return Callables.threadRenaming(command, nameSupplier); - } - }; - } - - /** - * Creates a {@link ScheduledExecutorService} that renames the {@link Thread threads} that its - * tasks run in. - * - *

The names are retrieved from the {@code nameSupplier} on the thread that is being renamed - * right before each task is run. The renaming is best effort, if a {@link SecurityManager} - * prevents the renaming then it will be skipped but the tasks will still execute. - * - * @param service The executor to decorate - * @param nameSupplier The source of names for each task - */ - @GwtIncompatible // concurrency - static ScheduledExecutorService renamingDecorator( - final ScheduledExecutorService service, final Supplier nameSupplier) { - checkNotNull(service); - checkNotNull(nameSupplier); - return new WrappingScheduledExecutorService(service) { - @Override - protected Callable wrapTask(Callable callable) { - return Callables.threadRenaming(callable, nameSupplier); - } - - @Override - protected Runnable wrapTask(Runnable command) { - return Callables.threadRenaming(command, nameSupplier); - } - }; - } - - /** - * Shuts down the given executor service gradually, first disabling new submissions and later, if - * necessary, cancelling remaining tasks. - * - *

The method takes the following steps: - * - *

    - *
  1. calls {@link ExecutorService#shutdown()}, disabling acceptance of new submitted tasks. - *
  2. awaits executor service termination for half of the specified timeout. - *
  3. if the timeout expires, it calls {@link ExecutorService#shutdownNow()}, cancelling - * pending tasks and interrupting running tasks. - *
  4. awaits executor service termination for the other half of the specified timeout. - *
- * - *

If, at any step of the process, the calling thread is interrupted, the method calls {@link - * ExecutorService#shutdownNow()} and returns. - * - * @param service the {@code ExecutorService} to shut down - * @param timeout the maximum time to wait for the {@code ExecutorService} to terminate - * @return {@code true} if the {@code ExecutorService} was terminated successfully, {@code false} - * if the call timed out or was interrupted - * @since 28.0 - */ - @Beta - @CanIgnoreReturnValue - @GwtIncompatible // java.time.Duration - public static boolean shutdownAndAwaitTermination(ExecutorService service, Duration timeout) { - return shutdownAndAwaitTermination(service, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); - } - - /** - * Shuts down the given executor service gradually, first disabling new submissions and later, if - * necessary, cancelling remaining tasks. - * - *

The method takes the following steps: - * - *

    - *
  1. calls {@link ExecutorService#shutdown()}, disabling acceptance of new submitted tasks. - *
  2. awaits executor service termination for half of the specified timeout. - *
  3. if the timeout expires, it calls {@link ExecutorService#shutdownNow()}, cancelling - * pending tasks and interrupting running tasks. - *
  4. awaits executor service termination for the other half of the specified timeout. - *
- * - *

If, at any step of the process, the calling thread is interrupted, the method calls {@link - * ExecutorService#shutdownNow()} and returns. - * - * @param service the {@code ExecutorService} to shut down - * @param timeout the maximum time to wait for the {@code ExecutorService} to terminate - * @param unit the time unit of the timeout argument - * @return {@code true} if the {@code ExecutorService} was terminated successfully, {@code false} - * if the call timed out or was interrupted - * @since 17.0 - */ - @Beta - @CanIgnoreReturnValue - @GwtIncompatible // concurrency - @SuppressWarnings("GoodTime") // should accept a java.time.Duration - public static boolean shutdownAndAwaitTermination( - ExecutorService service, long timeout, TimeUnit unit) { - long halfTimeoutNanos = unit.toNanos(timeout) / 2; - // Disable new tasks from being submitted - service.shutdown(); - try { - // Wait for half the duration of the timeout for existing tasks to terminate - if (!service.awaitTermination(halfTimeoutNanos, TimeUnit.NANOSECONDS)) { - // Cancel currently executing tasks - service.shutdownNow(); - // Wait the other half of the timeout for tasks to respond to being cancelled - service.awaitTermination(halfTimeoutNanos, TimeUnit.NANOSECONDS); - } - } catch (InterruptedException ie) { - // Preserve interrupt status - Thread.currentThread().interrupt(); - // (Re-)Cancel if current thread also interrupted - service.shutdownNow(); - } - return service.isTerminated(); - } - - /** - * Returns an Executor that will propagate {@link RejectedExecutionException} from the delegate - * executor to the given {@code future}. - * - *

Note, the returned executor can only be used once. - */ - static Executor rejectionPropagatingExecutor( - final Executor delegate, final AbstractFuture future) { - checkNotNull(delegate); - checkNotNull(future); - if (delegate == directExecutor()) { - // directExecutor() cannot throw RejectedExecutionException - return delegate; - } - return new Executor() { - @Override - public void execute(Runnable command) { - try { - delegate.execute(command); - } catch (RejectedExecutionException e) { - future.setException(e); - } - } - }; - } - - // Nacho start - /** - * Creates an executor service that runs each task in the thread that invokes {@code - * execute/submit}, as in {@code ThreadPoolExecutor.CallerRunsPolicy}. This applies both to - * individually submitted tasks and to collections of tasks submitted via {@code invokeAll} or - * {@code invokeAny}. In the latter case, tasks will run serially on the calling thread. Tasks are - * run to completion before a {@code Future} is returned to the caller (unless the executor has - * been shutdown). - * - *

Although all tasks are immediately executed in the thread that submitted the task, this - * {@code ExecutorService} imposes a small locking overhead on each task submission in order to - * implement shutdown and termination behavior. - * - *

The implementation deviates from the {@code ExecutorService} specification with regards to - * the {@code shutdownNow} method. First, "best-effort" with regards to canceling running tasks is - * implemented as "no-effort". No interrupts or other attempts are made to stop threads executing - * tasks. Second, the returned list will always be empty, as any submitted task is considered to - * have started execution. This applies also to tasks given to {@code invokeAll} or {@code - * invokeAny} which are pending serial execution, even the subset of the tasks that have not yet - * started execution. It is unclear from the {@code ExecutorService} specification if these should - * be included, and it's much easier to implement the interpretation that they not be. Finally, a - * call to {@code shutdown} or {@code shutdownNow} may result in concurrent calls to {@code - * invokeAll/invokeAny} throwing RejectedExecutionException, although a subset of the tasks may - * already have been executed. - * - * @since 10.0 - * @deprecated replaced by {@link MoreExecutors#sameThreadExecutor()} - * @see MoreExecutors#sameThreadExecutor() - */ - @Deprecated - @GwtIncompatible - public static ListeningExecutorService sameThreadExecutor() { - return newDirectExecutorService(); - } - // Nacho end -} \ No newline at end of file diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/AchievementCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/AchievementCommand.java deleted file mode 100644 index c2e179505..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/AchievementCommand.java +++ /dev/null @@ -1,188 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.Achievement; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Statistic; -import org.bukkit.Material; -import org.bukkit.Statistic.Type; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; -import org.bukkit.event.player.PlayerAchievementAwardedEvent; -import org.bukkit.event.player.PlayerStatisticIncrementEvent; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class AchievementCommand extends VanillaCommand { - public AchievementCommand() { - super("achievement"); - this.description = "Gives the specified player an achievement or changes a statistic value. Use '*' to give all achievements."; - this.usageMessage = "/achievement give [player]"; - this.setPermission("bukkit.command.achievement"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - - if (args.length < 2) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - if (!args[0].equalsIgnoreCase("give")) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - String statisticString = args[1]; - Player player = null; - - if (args.length > 2) { - player = Bukkit.getPlayer(args[1]); - } else if (sender instanceof Player) { - player = (Player) sender; - } - - if (player == null) { - sender.sendMessage("You must specify which player you wish to perform this action on."); - return true; - } - - if (statisticString.equals("*")) { - for (Achievement achievement : Achievement.values()) { - if (player.hasAchievement(achievement)) { - continue; - } - PlayerAchievementAwardedEvent event = new PlayerAchievementAwardedEvent(player, achievement); - Bukkit.getServer().getPluginManager().callEvent(event); - if (!event.isCancelled()) { - player.awardAchievement(achievement); - } - } - Command.broadcastCommandMessage(sender, String.format("Successfully given all achievements to %s", player.getName())); - return true; - } - - Achievement achievement = Bukkit.getUnsafe().getAchievementFromInternalName(statisticString); - Statistic statistic = Bukkit.getUnsafe().getStatisticFromInternalName(statisticString); - - if (achievement != null) { - if (player.hasAchievement(achievement)) { - sender.sendMessage(String.format("%s already has achievement %s", player.getName(), statisticString)); - return true; - } - - PlayerAchievementAwardedEvent event = new PlayerAchievementAwardedEvent(player, achievement); - Bukkit.getServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - sender.sendMessage(String.format("Unable to award %s the achievement %s", player.getName(), statisticString)); - return true; - } - player.awardAchievement(achievement); - - Command.broadcastCommandMessage(sender, String.format("Successfully given %s the stat %s", player.getName(), statisticString)); - return true; - } - - if (statistic == null) { - sender.sendMessage(String.format("Unknown achievement or statistic '%s'", statisticString)); - return true; - } - - if (statistic.getType() == Type.UNTYPED) { - PlayerStatisticIncrementEvent event = new PlayerStatisticIncrementEvent(player, statistic, player.getStatistic(statistic), player.getStatistic(statistic) + 1); - Bukkit.getServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - sender.sendMessage(String.format("Unable to increment %s for %s", statisticString, player.getName())); - return true; - } - player.incrementStatistic(statistic); - Command.broadcastCommandMessage(sender, String.format("Successfully given %s the stat %s", player.getName(), statisticString)); - return true; - } - - if (statistic.getType() == Type.ENTITY) { - EntityType entityType = EntityType.fromName(statisticString.substring(statisticString.lastIndexOf(".") + 1)); - - if (entityType == null) { - sender.sendMessage(String.format("Unknown achievement or statistic '%s'", statisticString)); - return true; - } - - PlayerStatisticIncrementEvent event = new PlayerStatisticIncrementEvent(player, statistic, player.getStatistic(statistic), player.getStatistic(statistic) + 1, entityType); - Bukkit.getServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - sender.sendMessage(String.format("Unable to increment %s for %s", statisticString, player.getName())); - return true; - } - - try { - player.incrementStatistic(statistic, entityType); - } catch (IllegalArgumentException e) { - sender.sendMessage(String.format("Unknown achievement or statistic '%s'", statisticString)); - return true; - } - } else { - int id; - try { - id = getInteger(sender, statisticString.substring(statisticString.lastIndexOf(".") + 1), 0, Integer.MAX_VALUE, true); - } catch (NumberFormatException e) { - sender.sendMessage(e.getMessage()); - return true; - } - - Material material = Material.getMaterial(id); - - if (material == null) { - sender.sendMessage(String.format("Unknown achievement or statistic '%s'", statisticString)); - return true; - } - - PlayerStatisticIncrementEvent event = new PlayerStatisticIncrementEvent(player, statistic, player.getStatistic(statistic), player.getStatistic(statistic) + 1, material); - Bukkit.getServer().getPluginManager().callEvent(event); - if (event.isCancelled()) { - sender.sendMessage(String.format("Unable to increment %s for %s", statisticString, player.getName())); - return true; - } - - try { - player.incrementStatistic(statistic, material); - } catch (IllegalArgumentException e) { - sender.sendMessage(String.format("Unknown achievement or statistic '%s'", statisticString)); - return true; - } - } - - Command.broadcastCommandMessage(sender, String.format("Successfully given %s the stat %s", player.getName(), statisticString)); - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length == 1) { - return Arrays.asList("give"); - } - - if (args.length == 2) { - return Bukkit.getUnsafe().tabCompleteInternalStatisticOrAchievementName(args[1], new ArrayList()); - } - - if (args.length == 3) { - return super.tabComplete(sender, alias, args); - } - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/BanCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/BanCommand.java deleted file mode 100644 index 59b804ce6..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/BanCommand.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.List; - -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.Validate; -import org.bukkit.BanList; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class BanCommand extends VanillaCommand { - public BanCommand() { - super("ban"); - this.description = "Prevents the specified player from using this server"; - this.usageMessage = "/ban [reason ...]"; - this.setPermission("bukkit.command.ban.player"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - if (args.length == 0) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - String reason = args.length > 0 ? StringUtils.join(args, ' ', 1, args.length) : null; - Bukkit.getBanList(BanList.Type.NAME).addBan(args[0], reason, null, sender.getName()); - - Player player = Bukkit.getPlayer(args[0]); - if (player != null) { - player.kickPlayer("Banned by admin."); - } - - Command.broadcastCommandMessage(sender, "Banned player " + args[0]); - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length >= 1) { - return super.tabComplete(sender, alias, args); - } - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/BanIpCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/BanIpCommand.java deleted file mode 100644 index 9fcd04663..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/BanIpCommand.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.List; -import java.util.regex.Pattern; - -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.Validate; -import org.bukkit.BanList; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class BanIpCommand extends VanillaCommand { - public static final Pattern ipValidity = Pattern.compile("^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])$"); - - public BanIpCommand() { - super("ban-ip"); - this.description = "Prevents the specified IP address from using this server"; - this.usageMessage = "/ban-ip [reason ...]"; - this.setPermission("bukkit.command.ban.ip"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - if (args.length < 1) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - String reason = args.length > 0 ? StringUtils.join(args, ' ', 1, args.length) : null; - - if (ipValidity.matcher(args[0]).matches()) { - processIPBan(args[0], sender, reason); - } else { - Player player = Bukkit.getPlayer(args[0]); - - if (player == null) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - processIPBan(player.getAddress().getAddress().getHostAddress(), sender, reason); - } - - return true; - } - - private void processIPBan(String ip, CommandSender sender, String reason) { - Bukkit.getBanList(BanList.Type.IP).addBan(ip, reason, null, sender.getName()); - - // Find all matching players and kick - for (Player player : Bukkit.getOnlinePlayers()) { - if (player.getAddress().getAddress().getHostAddress().equals(ip)) { - player.kickPlayer("You have been IP banned."); - } - } - - Command.broadcastCommandMessage(sender, "Banned IP Address " + ip); - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length == 1) { - return super.tabComplete(sender, alias, args); - } - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/BanListCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/BanListCommand.java deleted file mode 100644 index 182914342..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/BanListCommand.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.BanEntry; -import org.bukkit.BanList; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; -import org.bukkit.util.StringUtil; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class BanListCommand extends VanillaCommand { - private static final List BANLIST_TYPES = ImmutableList.of("ips", "players"); - - public BanListCommand() { - super("banlist"); - this.description = "View all players banned from this server"; - this.usageMessage = "/banlist [ips|players]"; - this.setPermission("bukkit.command.ban.list"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - - BanList.Type banType = BanList.Type.NAME; - if (args.length > 0) { - if (args[0].equalsIgnoreCase("ips")) { - banType = BanList.Type.IP; - } else if (!args[0].equalsIgnoreCase("players")) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - } - - StringBuilder message = new StringBuilder(); - BanEntry[] banlist = Bukkit.getBanList(banType).getBanEntries().toArray(new BanEntry[0]); - - for (int x = 0; x < banlist.length; x++) { - if (x != 0) { - if (x == banlist.length - 1) { - message.append(" and "); - } else { - message.append(", "); - } - } - - message.append(banlist[x].getTarget()); - } - - sender.sendMessage("There are " + banlist.length + " total banned players:"); - sender.sendMessage(message.toString()); - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length == 1) { - return StringUtil.copyPartialMatches(args[0], BANLIST_TYPES, new ArrayList(BANLIST_TYPES.size())); - } - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/ClearCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/ClearCommand.java deleted file mode 100644 index 05317e14a..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/ClearCommand.java +++ /dev/null @@ -1,115 +0,0 @@ -package org.bukkit.command.defaults; - -import com.google.common.collect.ImmutableList; -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.util.StringUtil; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -@Deprecated -public class ClearCommand extends VanillaCommand { - private static List materials; - static { - ArrayList materialList = new ArrayList(); - for (Material material : Material.values()) { - materialList.add(material.name()); - } - Collections.sort(materialList); - materials = ImmutableList.copyOf(materialList); - } - - public ClearCommand() { - super("clear"); - this.description = "Clears the player's inventory. Can specify item and data filters too."; - this.usageMessage = "/clear [item] [data]"; - this.setPermission("bukkit.command.clear"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - - Player player = null; - if (args.length > 0) { - player = Bukkit.getPlayer(args[0]); - } else if (sender instanceof Player) { - player = (Player) sender; - } - - if (player != null) { - int id; - - if (args.length > 1 && !(args[1].equals("-1"))) { - Material material = Material.matchMaterial(args[1]); - if (material == null) { - sender.sendMessage(ChatColor.RED + "There's no item called " + args[1]); - return false; - } - - id = material.getId(); - } else { - id = -1; - } - - int data = args.length >= 3 ? getInteger(sender, args[2], 0) : -1; - int count = player.getInventory().clear(id, data); - - Command.broadcastCommandMessage(sender, "Cleared the inventory of " + player.getDisplayName() + ", removing " + count + " items"); - } else if (args.length == 0) { - sender.sendMessage(ChatColor.RED + "Please provide a player!"); - } else { - sender.sendMessage(ChatColor.RED + "Can't find player " + args[0]); - } - - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length == 1) { - return super.tabComplete(sender, alias, args); - } - if (args.length == 2) { - final String arg = args[1]; - final List materials = ClearCommand.materials; - List completion = null; - - final int size = materials.size(); - int i = Collections.binarySearch(materials, arg, String.CASE_INSENSITIVE_ORDER); - - if (i < 0) { - // Insertion (start) index - i = -1 - i; - } - - for ( ; i < size; i++) { - String material = materials.get(i); - if (StringUtil.startsWithIgnoreCase(material, arg)) { - if (completion == null) { - completion = new ArrayList(); - } - completion.add(material); - } else { - break; - } - } - - if (completion != null) { - return completion; - } - } - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/DefaultGameModeCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/DefaultGameModeCommand.java deleted file mode 100644 index f217aea53..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/DefaultGameModeCommand.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.GameMode; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.util.StringUtil; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class DefaultGameModeCommand extends VanillaCommand { - private static final List GAMEMODE_NAMES = ImmutableList.of("adventure", "creative", "survival"); - - public DefaultGameModeCommand() { - super("defaultgamemode"); - this.description = "Set the default gamemode"; - this.usageMessage = "/defaultgamemode "; - this.setPermission("bukkit.command.defaultgamemode"); - } - - @Override - public boolean execute(CommandSender sender, String commandLabel, String[] args) { - if (!testPermission(sender)) return true; - if (args.length == 0) { - sender.sendMessage("Usage: " + usageMessage); - return false; - } - - String modeArg = args[0]; - int value = -1; - - try { - value = Integer.parseInt(modeArg); - } catch (NumberFormatException ex) {} - - GameMode mode = GameMode.getByValue(value); - - if (mode == null) { - if (modeArg.equalsIgnoreCase("creative") || modeArg.equalsIgnoreCase("c")) { - mode = GameMode.CREATIVE; - } else if (modeArg.equalsIgnoreCase("adventure") || modeArg.equalsIgnoreCase("a")) { - mode = GameMode.ADVENTURE; - } else { - mode = GameMode.SURVIVAL; - } - } - - Bukkit.getServer().setDefaultGameMode(mode); - Command.broadcastCommandMessage(sender, "Default game mode set to " + mode.toString().toLowerCase()); - - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length == 1) { - return StringUtil.copyPartialMatches(args[0], GAMEMODE_NAMES, new ArrayList(GAMEMODE_NAMES.size())); - } - - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/DeopCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/DeopCommand.java deleted file mode 100644 index 86be15ea5..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/DeopCommand.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.util.StringUtil; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class DeopCommand extends VanillaCommand { - public DeopCommand() { - super("deop"); - this.description = "Takes the specified player's operator status"; - this.usageMessage = "/deop "; - this.setPermission("bukkit.command.op.take"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - if (args.length != 1 || args[0].length() == 0) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - OfflinePlayer player = Bukkit.getOfflinePlayer(args[0]); - player.setOp(false); - - if (player instanceof Player) { - ((Player) player).sendMessage(ChatColor.YELLOW + "You are no longer op!"); - } - - Command.broadcastCommandMessage(sender, "De-opped " + args[0]); - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length == 1) { - List completions = new ArrayList(); - for (OfflinePlayer player : Bukkit.getOperators()) { - String playerName = player.getName(); - if (StringUtil.startsWithIgnoreCase(playerName, args[0])) { - completions.add(playerName); - } - } - return completions; - } - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/DifficultyCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/DifficultyCommand.java deleted file mode 100644 index 74a8ac2ae..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/DifficultyCommand.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.bukkit.command.defaults; - -import com.google.common.collect.ImmutableList; -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.util.StringUtil; -import org.bukkit.Difficulty; - -import java.util.ArrayList; -import java.util.List; - -@Deprecated -public class DifficultyCommand extends VanillaCommand { - private static final List DIFFICULTY_NAMES = ImmutableList.of("peaceful", "easy", "normal", "hard"); - - public DifficultyCommand() { - super("difficulty"); - this.description = "Sets the game difficulty"; - this.usageMessage = "/difficulty "; - this.setPermission("bukkit.command.difficulty"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - if (args.length != 1 || args[0].length() == 0) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - Difficulty difficulty = Difficulty.getByValue(getDifficultyForString(sender, args[0])); - - if (Bukkit.isHardcore()) { - difficulty = Difficulty.HARD; - } - - Bukkit.getWorlds().get(0).setDifficulty(difficulty); - - int levelCount = 1; - if (Bukkit.getAllowNether()) { - Bukkit.getWorlds().get(levelCount).setDifficulty(difficulty); - levelCount++; - } - - if (Bukkit.getAllowEnd()) { - Bukkit.getWorlds().get(levelCount).setDifficulty(difficulty); - } - - Command.broadcastCommandMessage(sender, "Set difficulty to " + difficulty.toString()); - return true; - } - - protected int getDifficultyForString(CommandSender sender, String name) { - if (name.equalsIgnoreCase("peaceful") || name.equalsIgnoreCase("p")) { - return 0; - } else if (name.equalsIgnoreCase("easy") || name.equalsIgnoreCase("e")) { - return 1; - } else if (name.equalsIgnoreCase("normal") || name.equalsIgnoreCase("n")) { - return 2; - } else if (name.equalsIgnoreCase("hard") || name.equalsIgnoreCase("h")) { - return 3; - } else { - return getInteger(sender, name, 0, 3); - } - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length == 1) { - return StringUtil.copyPartialMatches(args[0], DIFFICULTY_NAMES, new ArrayList(DIFFICULTY_NAMES.size())); - } - - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/EffectCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/EffectCommand.java deleted file mode 100644 index de63bbe1d..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/EffectCommand.java +++ /dev/null @@ -1,120 +0,0 @@ -package org.bukkit.command.defaults; - -import com.google.common.collect.ImmutableList; -import java.util.ArrayList; -import java.util.List; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; -import org.bukkit.util.StringUtil; - -@Deprecated -public class EffectCommand extends VanillaCommand { - private static final List effects; - - public EffectCommand() { - super("effect"); - this.description = "Adds/Removes effects on players"; - this.usageMessage = "/effect [seconds] [amplifier]"; - this.setPermission("bukkit.command.effect"); - } - - static { - ImmutableList.Builder builder = ImmutableList.builder(); - - for (PotionEffectType type : PotionEffectType.values()) { - if (type != null) { - builder.add(type.getName()); - } - } - - effects = builder.build(); - } - - @Override - public boolean execute(CommandSender sender, String commandLabel, String[] args) { - if (!testPermission(sender)) { - return true; - } - - if (args.length < 2) { - sender.sendMessage(getUsage()); - return true; - } - - final Player player = sender.getServer().getPlayer(args[0]); - - if (player == null) { - sender.sendMessage(ChatColor.RED + String.format("Player, %s, not found", args[0])); - return true; - } - - if ("clear".equalsIgnoreCase(args[1])) { - for (PotionEffect effect : player.getActivePotionEffects()) { - player.removePotionEffect(effect.getType()); - } - sender.sendMessage(String.format("Took all effects from %s", args[0])); - return true; - } - - PotionEffectType effect = PotionEffectType.getByName(args[1]); - - if (effect == null) { - effect = PotionEffectType.getById(getInteger(sender, args[1], 0)); - } - - if (effect == null) { - sender.sendMessage(ChatColor.RED + String.format("Effect, %s, not found", args[1])); - return true; - } - - int duration = 600; - int duration_temp = 30; - int amplification = 0; - - if (args.length >= 3) { - duration_temp = getInteger(sender, args[2], 0, 1000000); - if (effect.isInstant()) { - duration = duration_temp; - } else { - duration = duration_temp * 20; - } - } else if (effect.isInstant()) { - duration = 1; - } - - if (args.length >= 4) { - amplification = getInteger(sender, args[3], 0, 255); - } - - if (duration_temp == 0) { - if (!player.hasPotionEffect(effect)) { - sender.sendMessage(String.format("Couldn't take %s from %s as they do not have the effect", effect.getName(), args[0])); - return true; - } - - player.removePotionEffect(effect); - broadcastCommandMessage(sender, String.format("Took %s from %s", effect.getName(), args[0])); - } else { - final PotionEffect applyEffect = new PotionEffect(effect, duration, amplification); - - player.addPotionEffect(applyEffect, true); - broadcastCommandMessage(sender, String.format("Given %s (ID %d) * %d to %s for %d seconds", effect.getName(), effect.getId(), amplification, args[0], duration_temp)); - } - - return true; - } - - @Override - public List tabComplete(CommandSender sender, String commandLabel, String[] args) { - if (args.length == 1) { - return super.tabComplete(sender, commandLabel, args); - } else if (args.length == 2) { - return StringUtil.copyPartialMatches(args[1], effects, new ArrayList(effects.size())); - } - - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/EnchantCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/EnchantCommand.java deleted file mode 100644 index 5f0b6864b..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/EnchantCommand.java +++ /dev/null @@ -1,170 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import org.apache.commons.lang.Validate; -import org.apache.commons.lang.WordUtils; -import com.google.common.collect.ImmutableList; - -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.util.StringUtil; - -@Deprecated -public class EnchantCommand extends VanillaCommand { - private static final List ENCHANTMENT_NAMES = new ArrayList(); - - public EnchantCommand() { - super("enchant"); - this.description = "Adds enchantments to the item the player is currently holding. Specify 0 for the level to remove an enchantment. Specify force to ignore normal enchantment restrictions"; - this.usageMessage = "/enchant [level|max|0] [force]"; - this.setPermission("bukkit.command.enchant"); - } - - @Override - public boolean execute(CommandSender sender, String commandLabel, String[] args) { - if (!testPermission(sender)) return true; - if (args.length < 2) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - boolean force = false; - if (args.length > 2) { - force = args[args.length > 3 ? 3 : 2].equalsIgnoreCase("force"); - } - - Player player = Bukkit.getPlayerExact(args[0]); - if (player == null) { - sender.sendMessage("Can't find player " + args[0]); - } else { - ItemStack item = player.getItemInHand(); - if (item.getType() == Material.AIR) { - sender.sendMessage("The player isn't holding an item"); - } else { - String itemName = item.getType().toString().replaceAll("_", " "); - itemName = WordUtils.capitalizeFully(itemName); - - Enchantment enchantment = getEnchantment(args[1].toUpperCase()); - if (enchantment == null) { - sender.sendMessage(String.format("Enchantment does not exist: %s", args[1])); - } else { - String enchantmentName = enchantment.getName().replaceAll("_", " "); - enchantmentName = WordUtils.capitalizeFully(enchantmentName); - - if (!force && !enchantment.canEnchantItem(item)) { - sender.sendMessage(String.format("%s cannot be applied to %s", enchantmentName, itemName)); - } else { - int level = 1; - if (args.length > 2) { - Integer integer = getInteger(args[2]); - int minLevel = enchantment.getStartLevel(); - int maxLevel = force ? Short.MAX_VALUE : enchantment.getMaxLevel(); - - if (integer != null) { - if (integer == 0) { - item.removeEnchantment(enchantment); - Command.broadcastCommandMessage(sender, String.format("Removed %s on %s's %s", enchantmentName, player.getName(), itemName)); - return true; - } - - if (integer < minLevel || integer > maxLevel) { - sender.sendMessage(String.format("Level for enchantment %s must be between %d and %d", enchantmentName, minLevel, maxLevel)); - sender.sendMessage("Specify 0 for level to remove an enchantment"); - return true; - } - - level = integer; - } - - if ("max".equals(args[2])) { - level = maxLevel; - } - } - - Map enchantments = item.getEnchantments(); - boolean conflicts = false; - - if (!force && !enchantments.isEmpty()) { // TODO: Improve this to use a "hasEnchantments" call - for (Map.Entry entry : enchantments.entrySet()) { - Enchantment enchant = entry.getKey(); - - if (enchant.equals(enchantment)) continue; - if (enchant.conflictsWith(enchantment)) { - sender.sendMessage(String.format("Can't apply the enchantment %s on an item with the enchantment %s", enchantmentName, WordUtils.capitalizeFully(enchant.getName().replaceAll("_", " ")))); - conflicts = true; - break; - } - } - } - - if (!conflicts) { - item.addUnsafeEnchantment(enchantment, level); - - Command.broadcastCommandMessage(sender, String.format("Applied %s (Lvl %d) on %s's %s", enchantmentName, level, player.getName(), itemName), false); - sender.sendMessage(String.format("Enchanting succeeded, applied %s (Lvl %d) onto your %s", enchantmentName, level, itemName)); - } - } - } - } - } - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length == 1) { - return super.tabComplete(sender, alias, args); - } - - if (args.length == 2) { - return StringUtil.copyPartialMatches(args[1], ENCHANTMENT_NAMES, new ArrayList(ENCHANTMENT_NAMES.size())); - } - - if (args.length == 3 || args.length == 4) { - if (!args[args.length - 2].equalsIgnoreCase("force")) { - return ImmutableList.of("force"); - } - } - - return ImmutableList.of(); - } - - private Enchantment getEnchantment(String lookup) { - Enchantment enchantment = Enchantment.getByName(lookup); - - if (enchantment == null) { - Integer id = getInteger(lookup); - if (id != null) { - enchantment = Enchantment.getById(id); - } - } - - return enchantment; - } - - public static void buildEnchantments() { - if (!ENCHANTMENT_NAMES.isEmpty()) { - throw new IllegalStateException("Enchantments have already been built!"); - } - - for (Enchantment enchantment : Enchantment.values()) { - ENCHANTMENT_NAMES.add(enchantment.getName()); - } - - Collections.sort(ENCHANTMENT_NAMES); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/ExpCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/ExpCommand.java deleted file mode 100644 index aa33c0c51..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/ExpCommand.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class ExpCommand extends VanillaCommand { - public ExpCommand() { - super("xp"); - this.description = "Gives the specified player a certain amount of experience. Specify L to give levels instead, with a negative amount resulting in taking levels."; - this.usageMessage = "/xp [player] OR /xp L [player]"; - this.setPermission("bukkit.command.xp"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - - if (args.length > 0) { - String inputAmount = args[0]; - Player player = null; - - boolean isLevel = inputAmount.endsWith("l") || inputAmount.endsWith("L"); - if (isLevel && inputAmount.length() > 1) { - inputAmount = inputAmount.substring(0, inputAmount.length() - 1); - } - - int amount = getInteger(sender, inputAmount, Integer.MIN_VALUE, Integer.MAX_VALUE); - boolean isTaking = amount < 0; - - if (isTaking) { - amount *= -1; - } - - if (args.length > 1) { - player = Bukkit.getPlayer(args[1]); - } else if (sender instanceof Player) { - player = (Player) sender; - } - - if (player != null) { - if (isLevel) { - if (isTaking) { - player.giveExpLevels(-amount); - Command.broadcastCommandMessage(sender, "Taken " + amount + " level(s) from " + player.getName()); - } else { - player.giveExpLevels(amount); - Command.broadcastCommandMessage(sender, "Given " + amount + " level(s) to " + player.getName()); - } - } else { - if (isTaking) { - sender.sendMessage(ChatColor.RED + "Taking experience can only be done by levels, cannot give players negative experience points"); - return false; - } else { - player.giveExp(amount); - Command.broadcastCommandMessage(sender, "Given " + amount + " experience to " + player.getName()); - } - } - } else { - sender.sendMessage("Can't find player, was one provided?\n" + ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - return true; - } - - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length == 2) { - return super.tabComplete(sender, alias, args); - } - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/GameModeCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/GameModeCommand.java deleted file mode 100644 index f9675a053..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/GameModeCommand.java +++ /dev/null @@ -1,101 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.GameMode; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.util.StringUtil; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class GameModeCommand extends VanillaCommand { - private static final List GAMEMODE_NAMES = ImmutableList.of("adventure", "creative", "survival", "spectator"); - - public GameModeCommand() { - super("gamemode"); - this.description = "Changes the player to a specific game mode"; - this.usageMessage = "/gamemode [player]"; - this.setPermission("bukkit.command.gamemode"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - if (args.length == 0) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - String modeArg = args[0]; - String playerArg = sender.getName(); - - if (args.length == 2) { - playerArg = args[1]; - } - - Player player = Bukkit.getPlayerExact(playerArg); - - if (player != null) { - int value = -1; - - try { - value = Integer.parseInt(modeArg); - } catch (NumberFormatException ex) {} - - GameMode mode = GameMode.getByValue(value); - - if (mode == null) { - if (modeArg.equalsIgnoreCase("creative") || modeArg.equalsIgnoreCase("c")) { - mode = GameMode.CREATIVE; - } else if (modeArg.equalsIgnoreCase("adventure") || modeArg.equalsIgnoreCase("a")) { - mode = GameMode.ADVENTURE; - } else if (modeArg.equalsIgnoreCase("spectator") || modeArg.equalsIgnoreCase("sp")) { - mode = GameMode.SPECTATOR; - } else { - mode = GameMode.SURVIVAL; - } - } - - if (mode != player.getGameMode()) { - player.setGameMode(mode); - - if (mode != player.getGameMode()) { - sender.sendMessage("Game mode change for " + player.getName() + " failed!"); - } else { - if (player == sender) { - Command.broadcastCommandMessage(sender, "Set own game mode to " + mode.toString() + " mode"); - } else { - Command.broadcastCommandMessage(sender, "Set " + player.getName() + "'s game mode to " + mode.toString() + " mode"); - } - } - } else { - sender.sendMessage(player.getName() + " already has game mode " + mode.getValue()); - } - } else { - sender.sendMessage("Can't find player " + playerArg); - } - - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length == 1) { - return StringUtil.copyPartialMatches(args[0], GAMEMODE_NAMES, new ArrayList(GAMEMODE_NAMES.size())); - } else if (args.length == 2) { - return super.tabComplete(sender, alias, args); - } - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/GameRuleCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/GameRuleCommand.java deleted file mode 100644 index 13e258926..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/GameRuleCommand.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.bukkit.command.defaults; - -import com.google.common.collect.ImmutableList; -import org.apache.commons.lang.Validate; -import org.bukkit.ChatColor; -import org.bukkit.command.BlockCommandSender; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.util.StringUtil; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.entity.HumanEntity; - -@Deprecated -public class GameRuleCommand extends VanillaCommand { - private static final List GAMERULE_STATES = ImmutableList.of("true", "false"); - - public GameRuleCommand() { - super("gamerule"); - this.description = "Sets a server's game rules"; - this.usageMessage = "/gamerule OR /gamerule "; - this.setPermission("bukkit.command.gamerule"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - - if (args.length > 0) { - String rule = args[0]; - World world = getGameWorld(sender); - - if (world.isGameRule(rule)) { - if (args.length > 1) { - String value = args[1]; - - world.setGameRuleValue(rule, value); - Command.broadcastCommandMessage(sender, "Game rule " + rule + " has been set to: " + value); - } else { - String value = world.getGameRuleValue(rule); - sender.sendMessage(rule + " = " + value); - } - } else { - sender.sendMessage(ChatColor.RED + "No game rule called " + rule + " is available"); - } - - return true; - } else { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - sender.sendMessage("Rules: " + this.createString(getGameWorld(sender).getGameRules(), 0, ", ")); - - return true; - } - } - - private World getGameWorld(CommandSender sender) { - if (sender instanceof HumanEntity) { - World world = ((HumanEntity) sender).getWorld(); - if (world != null) { - return world; - } - } else if (sender instanceof BlockCommandSender) { - return ((BlockCommandSender) sender).getBlock().getWorld(); - } - - return Bukkit.getWorlds().get(0); - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length == 1) { - return StringUtil.copyPartialMatches(args[0], Arrays.asList(getGameWorld(sender).getGameRules()), new ArrayList()); - } - - if (args.length == 2) { - return StringUtil.copyPartialMatches(args[1], GAMERULE_STATES, new ArrayList(GAMERULE_STATES.size())); - } - - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/GiveCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/GiveCommand.java deleted file mode 100644 index c8b7f0f95..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/GiveCommand.java +++ /dev/null @@ -1,130 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.util.StringUtil; - -import com.google.common.base.Joiner; -import com.google.common.collect.ImmutableList; - -@Deprecated -public class GiveCommand extends VanillaCommand { - private static List materials; - static { - ArrayList materialList = new ArrayList(); - for (Material material : Material.values()) { - materialList.add(material.name()); - } - Collections.sort(materialList); - materials = ImmutableList.copyOf(materialList); - } - - public GiveCommand() { - super("give"); - this.description = "Gives the specified player a certain amount of items"; - this.usageMessage = "/give [amount [data]]"; - this.setPermission("bukkit.command.give"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - if ((args.length < 2)) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - Player player = Bukkit.getPlayerExact(args[0]); - - if (player != null) { - Material material = Material.matchMaterial(args[1]); - - if (material == null) { - material = Bukkit.getUnsafe().getMaterialFromInternalName(args[1]); - } - - if (material != null) { - int amount = 1; - short data = 0; - - if (args.length >= 3) { - amount = this.getInteger(sender, args[2], 1, 64); - - if (args.length >= 4) { - try { - data = Short.parseShort(args[3]); - } catch (NumberFormatException ex) {} - } - } - - ItemStack stack = new ItemStack(material, amount, data); - - if (args.length >= 5) { - try { - stack = Bukkit.getUnsafe().modifyItemStack(stack, Joiner.on(' ').join(Arrays.asList(args).subList(4, args.length))); - } catch (Throwable t) { - player.sendMessage("Not a valid tag"); - return true; - } - } - - player.getInventory().addItem(stack); - - Command.broadcastCommandMessage(sender, "Gave " + player.getName() + " some " + material.getId() + " (" + material + ")"); - } else { - sender.sendMessage("There's no item called " + args[1]); - } - } else { - sender.sendMessage("Can't find player " + args[0]); - } - - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length == 1) { - return super.tabComplete(sender, alias, args); - } - if (args.length == 2) { - final String arg = args[1]; - final List materials = GiveCommand.materials; - List completion = new ArrayList(); - - final int size = materials.size(); - int i = Collections.binarySearch(materials, arg, String.CASE_INSENSITIVE_ORDER); - - if (i < 0) { - // Insertion (start) index - i = -1 - i; - } - - for ( ; i < size; i++) { - String material = materials.get(i); - if (StringUtil.startsWithIgnoreCase(material, arg)) { - completion.add(material); - } else { - break; - } - } - - return Bukkit.getUnsafe().tabCompleteInternalMaterialName(arg, completion); - } - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/KickCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/KickCommand.java deleted file mode 100644 index 634c115a6..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/KickCommand.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class KickCommand extends VanillaCommand { - public KickCommand() { - super("kick"); - this.description = "Removes the specified player from the server"; - this.usageMessage = "/kick [reason ...]"; - this.setPermission("bukkit.command.kick"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - if (args.length < 1 || args[0].length() == 0) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - Player player = Bukkit.getPlayerExact(args[0]); - - if (player != null) { - String reason = "Kicked by an operator."; - - if (args.length > 1) { - reason = createString(args, 1); - } - - player.kickPlayer(reason); - Command.broadcastCommandMessage(sender, "Kicked player " + player.getName() + ". With reason:\n" + reason); - } else { - sender.sendMessage( args[0] + " not found."); - } - - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length >= 1) { - return super.tabComplete(sender, alias, args); - } - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/KillCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/KillCommand.java deleted file mode 100644 index 2143eb181..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/KillCommand.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.event.entity.EntityDamageEvent; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class KillCommand extends VanillaCommand { - public KillCommand() { - super("kill"); - this.description = "Commits suicide, only usable as a player"; - this.usageMessage = "/kill"; - this.setPermission("bukkit.command.kill"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - - if (sender instanceof Player) { - Player player = (Player) sender; - - EntityDamageEvent ede = new EntityDamageEvent(player, EntityDamageEvent.DamageCause.SUICIDE, 1000); - Bukkit.getPluginManager().callEvent(ede); - if (ede.isCancelled()) return true; - - ede.getEntity().setLastDamageCause(ede); - player.setHealth(0); - sender.sendMessage("Ouch. That look like it hurt."); - } else { - sender.sendMessage("You can only perform this command as a player"); - } - - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/ListCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/ListCommand.java deleted file mode 100644 index ea62bee3e..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/ListCommand.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.Collection; -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class ListCommand extends VanillaCommand { - public ListCommand() { - super("list"); - this.description = "Lists all online players"; - this.usageMessage = "/list"; - this.setPermission("bukkit.command.list"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - - StringBuilder online = new StringBuilder(); - - final Collection players = Bukkit.getOnlinePlayers(); - - for (Player player : players) { - // If a player is hidden from the sender don't show them in the list - if (sender instanceof Player && !((Player) sender).canSee(player)) - continue; - - if (online.length() > 0) { - online.append(", "); - } - - online.append(player.getDisplayName()); - } - - sender.sendMessage("There are " + players.size() + "/" + Bukkit.getMaxPlayers() + " players online:\n" + online.toString()); - - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/MeCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/MeCommand.java deleted file mode 100644 index 2a029cbe0..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/MeCommand.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.bukkit.command.defaults; - -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; - -@Deprecated -public class MeCommand extends VanillaCommand { - public MeCommand() { - super("me"); - this.description = "Performs the specified action in chat"; - this.usageMessage = "/me "; - this.setPermission("bukkit.command.me"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - if (args.length < 1) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - StringBuilder message = new StringBuilder(); - message.append(sender.getName()); - - for (String arg : args) { - message.append(" "); - message.append(arg); - } - - Bukkit.broadcastMessage("* " + message); - - return true; - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/OpCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/OpCommand.java deleted file mode 100644 index f5bb8b153..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/OpCommand.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.util.StringUtil; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class OpCommand extends VanillaCommand { - public OpCommand() { - super("op"); - this.description = "Gives the specified player operator status"; - this.usageMessage = "/op "; - this.setPermission("bukkit.command.op.give"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - if (args.length != 1 || args[0].length() == 0) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - OfflinePlayer player = Bukkit.getOfflinePlayer(args[0]); - player.setOp(true); - - Command.broadcastCommandMessage(sender, "Opped " + args[0]); - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length == 1) { - if (!(sender instanceof Player)) { - return ImmutableList.of(); - } - - String lastWord = args[0]; - if (lastWord.length() == 0) { - return ImmutableList.of(); - } - - Player senderPlayer = (Player) sender; - - ArrayList matchedPlayers = new ArrayList(); - for (Player player : sender.getServer().getOnlinePlayers()) { - String name = player.getName(); - if (!senderPlayer.canSee(player) || player.isOp()) { - continue; - } - if (StringUtil.startsWithIgnoreCase(name, lastWord)) { - matchedPlayers.add(name); - } - } - - Collections.sort(matchedPlayers, String.CASE_INSENSITIVE_ORDER); - return matchedPlayers; - } - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/PardonCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/PardonCommand.java deleted file mode 100644 index 762189a1e..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/PardonCommand.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.BanList; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.util.StringUtil; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class PardonCommand extends VanillaCommand { - public PardonCommand() { - super("pardon"); - this.description = "Allows the specified player to use this server"; - this.usageMessage = "/pardon "; - this.setPermission("bukkit.command.unban.player"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - if (args.length != 1) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - Bukkit.getBanList(BanList.Type.NAME).pardon(args[0]); - Command.broadcastCommandMessage(sender, "Pardoned " + args[0]); - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length == 1) { - List completions = new ArrayList(); - for (OfflinePlayer player : Bukkit.getBannedPlayers()) { - String name = player.getName(); - if (StringUtil.startsWithIgnoreCase(name, args[0])) { - completions.add(name); - } - } - return completions; - } - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/PardonIpCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/PardonIpCommand.java deleted file mode 100644 index 0f63c26bf..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/PardonIpCommand.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.util.StringUtil; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class PardonIpCommand extends VanillaCommand { - public PardonIpCommand() { - super("pardon-ip"); - this.description = "Allows the specified IP address to use this server"; - this.usageMessage = "/pardon-ip

"; - this.setPermission("bukkit.command.unban.ip"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - if (args.length != 1) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - if (BanIpCommand.ipValidity.matcher(args[0]).matches()) { - Bukkit.unbanIP(args[0]); - Command.broadcastCommandMessage(sender, "Pardoned ip " + args[0]); - } else { - sender.sendMessage("Invalid ip"); - } - - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length == 1) { - return StringUtil.copyPartialMatches(args[0], Bukkit.getIPBans(), new ArrayList()); - } - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/PlaySoundCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/PlaySoundCommand.java deleted file mode 100644 index a7737adbc..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/PlaySoundCommand.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.bukkit.command.defaults; - -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Location; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -@Deprecated -public class PlaySoundCommand extends VanillaCommand { - public PlaySoundCommand() { - super("playsound"); - this.description = "Plays a sound to a given player"; - this.usageMessage = "/playsound [x] [y] [z] [volume] [pitch] [minimumVolume]"; - this.setPermission("bukkit.command.playsound"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) { - return true; - } - - if (args.length < 2) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - final String soundArg = args[0]; - final String playerArg = args[1]; - - final Player player = Bukkit.getPlayerExact(playerArg); - if (player == null) { - sender.sendMessage(ChatColor.RED + "Can't find player " + playerArg); - return false; - } - - final Location location = player.getLocation(); - - double x = Math.floor(location.getX()); - double y = Math.floor(location.getY() + 0.5D); - double z = Math.floor(location.getZ()); - double volume = 1.0D; - double pitch = 1.0D; - double minimumVolume = 0.0D; - - switch (args.length) { - default: - case 8: - minimumVolume = getDouble(sender, args[7], 0.0D, 1.0D); - case 7: - pitch = getDouble(sender, args[6], 0.0D, 2.0D); - case 6: - volume = getDouble(sender, args[5], 0.0D, Float.MAX_VALUE); - case 5: - z = getRelativeDouble(z, sender, args[4]); - case 4: - y = getRelativeDouble(y, sender, args[3]); - case 3: - x = getRelativeDouble(x, sender, args[2]); - case 2: - // Noop - } - - final double fixedVolume = volume > 1.0D ? volume * 16.0D : 16.0D; - final Location soundLocation = new Location(player.getWorld(), x, y, z); - if (location.distanceSquared(soundLocation) > fixedVolume * fixedVolume) { - if (minimumVolume <= 0.0D) { - sender.sendMessage(ChatColor.RED + playerArg + " is too far away to hear the sound"); - return false; - } - - final double deltaX = x - location.getX(); - final double deltaY = y - location.getY(); - final double deltaZ = z - location.getZ(); - final double delta = Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ) / 2.0D; - - if (delta > 0.0D) { - location.add(deltaX / delta, deltaY / delta, deltaZ / delta); - } - - player.playSound(location, soundArg, (float) minimumVolume, (float) pitch); - } else { - player.playSound(soundLocation, soundArg, (float) volume, (float) pitch); - } - sender.sendMessage(String.format("Played '%s' to %s", soundArg, playerArg)); - return true; - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SaveCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SaveCommand.java deleted file mode 100644 index d08d3ed03..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SaveCommand.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class SaveCommand extends VanillaCommand { - public SaveCommand() { - super("save-all"); - this.description = "Saves the server to disk"; - this.usageMessage = "/save-all"; - this.setPermission("bukkit.command.save.perform"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - - Command.broadcastCommandMessage(sender, "Forcing save.."); - - Bukkit.savePlayers(); - - for (World world : Bukkit.getWorlds()) { - world.save(); - } - - Command.broadcastCommandMessage(sender, "Save complete."); - - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SaveOffCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SaveOffCommand.java deleted file mode 100644 index 54e6bca89..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SaveOffCommand.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class SaveOffCommand extends VanillaCommand { - public SaveOffCommand() { - super("save-off"); - this.description = "Disables server autosaving"; - this.usageMessage = "/save-off"; - this.setPermission("bukkit.command.save.disable"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - - for (World world : Bukkit.getWorlds()) { - world.setAutoSave(false); - } - - Command.broadcastCommandMessage(sender, "Disabled level saving.."); - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SaveOnCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SaveOnCommand.java deleted file mode 100644 index 760e1c483..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SaveOnCommand.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class SaveOnCommand extends VanillaCommand { - public SaveOnCommand() { - super("save-on"); - this.description = "Enables server autosaving"; - this.usageMessage = "/save-on"; - this.setPermission("bukkit.command.save.enable"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - - for (World world : Bukkit.getWorlds()) { - world.setAutoSave(true); - } - - Command.broadcastCommandMessage(sender, "Enabled level saving.."); - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SayCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SayCommand.java deleted file mode 100644 index 2b2a32a15..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SayCommand.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; -import org.bukkit.command.ConsoleCommandSender; -import org.bukkit.entity.Player; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class SayCommand extends VanillaCommand { - public SayCommand() { - super("say"); - this.description = "Broadcasts the given message as the sender"; - this.usageMessage = "/say "; - this.setPermission("bukkit.command.say"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - if (args.length == 0) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - StringBuilder message = new StringBuilder(); - message.append(ChatColor.LIGHT_PURPLE).append("["); - if (sender instanceof ConsoleCommandSender) { - message.append("Server"); - } else if (sender instanceof Player) { - message.append(((Player) sender).getDisplayName()); - } else { - message.append(sender.getName()); - } - message.append(ChatColor.LIGHT_PURPLE).append("] "); - - message.append(args[0]); - for (int i = 1; i < args.length; i++) { - message.append(" ").append(args[i]); - } - - Bukkit.broadcastMessage(message.toString()); - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - - if (args.length >= 1) { - return super.tabComplete(sender, alias, args); - } - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/ScoreboardCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/ScoreboardCommand.java deleted file mode 100644 index 00197f760..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/ScoreboardCommand.java +++ /dev/null @@ -1,618 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.lang.ArrayUtils; -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.scoreboard.DisplaySlot; -import org.bukkit.scoreboard.Objective; -import org.bukkit.scoreboard.Score; -import org.bukkit.scoreboard.Scoreboard; -import org.bukkit.scoreboard.Team; -import org.bukkit.util.StringUtil; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; - -@Deprecated -public class ScoreboardCommand extends VanillaCommand { - - private static final List MAIN_CHOICES = ImmutableList.of("objectives", "players", "teams"); - private static final List OBJECTIVES_CHOICES = ImmutableList.of("list", "add", "remove", "setdisplay"); - private static final List OBJECTIVES_CRITERIA = ImmutableList.of("health", "playerKillCount", "totalKillCount", "deathCount", "dummy"); - private static final List PLAYERS_CHOICES = ImmutableList.of("set", "add", "remove", "reset", "list"); - private static final List TEAMS_CHOICES = ImmutableList.of("add", "remove", "join", "leave", "empty", "list", "option"); - private static final List TEAMS_OPTION_CHOICES = ImmutableList.of("color", "friendlyfire", "seeFriendlyInvisibles"); - private static final Map OBJECTIVES_DISPLAYSLOT = ImmutableMap.of("belowName", DisplaySlot.BELOW_NAME, "list", DisplaySlot.PLAYER_LIST, "sidebar", DisplaySlot.SIDEBAR); - private static final Map TEAMS_OPTION_COLOR = ImmutableMap.builder() - .put("aqua", ChatColor.AQUA) - .put("black", ChatColor.BLACK) - .put("blue", ChatColor.BLUE) - .put("bold", ChatColor.BOLD) - .put("dark_aqua", ChatColor.DARK_AQUA) - .put("dark_blue", ChatColor.DARK_BLUE) - .put("dark_gray", ChatColor.DARK_GRAY) - .put("dark_green", ChatColor.DARK_GREEN) - .put("dark_purple", ChatColor.DARK_PURPLE) - .put("dark_red", ChatColor.DARK_RED) - .put("gold", ChatColor.GOLD) - .put("gray", ChatColor.GRAY) - .put("green", ChatColor.GREEN) - .put("italic", ChatColor.ITALIC) - .put("light_purple", ChatColor.LIGHT_PURPLE) - .put("obfuscated", ChatColor.MAGIC) // This is the important line - .put("red", ChatColor.RED) - .put("reset", ChatColor.RESET) - .put("strikethrough", ChatColor.STRIKETHROUGH) - .put("underline", ChatColor.UNDERLINE) - .put("white", ChatColor.WHITE) - .put("yellow", ChatColor.YELLOW) - .build(); - private static final List BOOLEAN = ImmutableList.of("true", "false"); - - public ScoreboardCommand() { - super("scoreboard"); - this.description = "Scoreboard control"; - this.usageMessage = "/scoreboard"; - this.setPermission("bukkit.command.scoreboard"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) - return true; - if (args.length < 1 || args[0].length() == 0) { - sender.sendMessage(ChatColor.RED + "Usage: /scoreboard "); - return false; - } - - final Scoreboard mainScoreboard = Bukkit.getScoreboardManager().getMainScoreboard(); - - if (args[0].equalsIgnoreCase("objectives")) { - if (args.length == 1) { - sender.sendMessage(ChatColor.RED + "Usage: /scoreboard objectives "); - return false; - } - if (args[1].equalsIgnoreCase("list")) { - Set objectives = mainScoreboard.getObjectives(); - if (objectives.isEmpty()) { - sender.sendMessage(ChatColor.RED + "There are no objectives on the scoreboard"); - return false; - } - sender.sendMessage(ChatColor.DARK_GREEN + "Showing " + objectives.size() + " objective(s) on scoreboard"); - for (Objective objective : objectives) { - sender.sendMessage("- " + objective.getName() + ": displays as '" + objective.getDisplayName() + "' and is type '" + objective.getCriteria() + "'"); - } - } else if (args[1].equalsIgnoreCase("add")) { - if (args.length < 4) { - sender.sendMessage(ChatColor.RED + "/scoreboard objectives add [display name ...]"); - return false; - } - String name = args[2]; - String criteria = args[3]; - - if (criteria == null) { - sender.sendMessage(ChatColor.RED + "Invalid objective criteria type. Valid types are: " + stringCollectionToString(OBJECTIVES_CRITERIA)); - } else if (name.length() > 16) { - sender.sendMessage(ChatColor.RED + "The name '" + name + "' is too long for an objective, it can be at most 16 characters long"); - } else if (mainScoreboard.getObjective(name) != null) { - sender.sendMessage(ChatColor.RED + "An objective with the name '" + name + "' already exists"); - } else { - String displayName = null; - if (args.length > 4) { - displayName = StringUtils.join(ArrayUtils.subarray(args, 4, args.length), ' '); - if (displayName.length() > 32) { - sender.sendMessage(ChatColor.RED + "The name '" + displayName + "' is too long for an objective, it can be at most 32 characters long"); - return false; - } - } - Objective objective = mainScoreboard.registerNewObjective(name, criteria); - if (displayName != null && displayName.length() > 0) { - objective.setDisplayName(displayName); - } - sender.sendMessage("Added new objective '" + name + "' successfully"); - } - } else if (args[1].equalsIgnoreCase("remove")) { - if (args.length != 3) { - sender.sendMessage(ChatColor.RED + "/scoreboard objectives remove "); - return false; - } - String name = args[2]; - Objective objective = mainScoreboard.getObjective(name); - if (objective == null) { - sender.sendMessage(ChatColor.RED + "No objective was found by the name '" + name + "'"); - } else { - objective.unregister(); - sender.sendMessage("Removed objective '" + name + "' successfully"); - } - } else if (args[1].equalsIgnoreCase("setdisplay")) { - if (args.length != 3 && args.length != 4) { - sender.sendMessage(ChatColor.RED + "/scoreboard objectives setdisplay [objective]"); - return false; - } - String slotName = args[2]; - DisplaySlot slot = OBJECTIVES_DISPLAYSLOT.get(slotName); - if (slot == null) { - sender.sendMessage(ChatColor.RED + "No such display slot '" + slotName + "'"); - } else { - if (args.length == 4) { - String objectiveName = args[3]; - Objective objective = mainScoreboard.getObjective(objectiveName); - if (objective == null) { - sender.sendMessage(ChatColor.RED + "No objective was found by the name '" + objectiveName + "'"); - return false; - } - - objective.setDisplaySlot(slot); - sender.sendMessage("Set the display objective in slot '" + slotName + "' to '" + objective.getName() + "'"); - } else { - Objective objective = mainScoreboard.getObjective(slot); - if (objective != null) { - objective.setDisplaySlot(null); - } - sender.sendMessage("Cleared objective display slot '" + slotName + "'"); - } - } - } - } else if (args[0].equalsIgnoreCase("players")) { - if (args.length == 1) { - sender.sendMessage(ChatColor.RED + "/scoreboard players "); - return false; - } - if (args[1].equalsIgnoreCase("set") || args[1].equalsIgnoreCase("add") || args[1].equalsIgnoreCase("remove")) { - if (args.length != 5) { - if (args[1].equalsIgnoreCase("set")) { - sender.sendMessage(ChatColor.RED + "/scoreboard players set "); - } else if (args[1].equalsIgnoreCase("add")) { - sender.sendMessage(ChatColor.RED + "/scoreboard players add "); - } else { - sender.sendMessage(ChatColor.RED + "/scoreboard players remove "); - } - return false; - } - String objectiveName = args[3]; - Objective objective = mainScoreboard.getObjective(objectiveName); - if (objective == null) { - sender.sendMessage(ChatColor.RED + "No objective was found by the name '" + objectiveName + "'"); - return false; - } else if (!objective.isModifiable()) { - sender.sendMessage(ChatColor.RED + "The objective '" + objectiveName + "' is read-only and cannot be set"); - return false; - } - - String valueString = args[4]; - int value; - try { - value = Integer.parseInt(valueString); - } catch (NumberFormatException e) { - sender.sendMessage(ChatColor.RED + "'" + valueString + "' is not a valid number"); - return false; - } - if (value < 1 && !args[1].equalsIgnoreCase("set")) { - sender.sendMessage(ChatColor.RED + "The number you have entered (" + value + ") is too small, it must be at least 1"); - return false; - } - - String playerName = args[2]; - if (playerName.length() > 16) { - sender.sendMessage(ChatColor.RED + "'" + playerName + "' is too long for a player name"); - return false; - } - Score score = objective.getScore(playerName); - int newScore; - if (args[1].equalsIgnoreCase("set")) { - newScore = value; - } else if (args[1].equalsIgnoreCase("add")) { - newScore = score.getScore() + value; - } else { - newScore = score.getScore() - value; - } - score.setScore(newScore); - sender.sendMessage("Set score of " + objectiveName + " for player " + playerName + " to " + newScore); - } else if (args[1].equalsIgnoreCase("reset")) { - if (args.length != 3) { - sender.sendMessage(ChatColor.RED + "/scoreboard players reset "); - return false; - } - String playerName = args[2]; - if (playerName.length() > 16) { - sender.sendMessage(ChatColor.RED + "'" + playerName + "' is too long for a player name"); - return false; - } - mainScoreboard.resetScores(playerName); - sender.sendMessage("Reset all scores of player " + playerName); - } else if (args[1].equalsIgnoreCase("list")) { - if (args.length > 3) { - sender.sendMessage(ChatColor.RED + "/scoreboard players list "); - return false; - } - if (args.length == 2) { - Set entries = mainScoreboard.getEntries(); - if (entries.isEmpty()) { - sender.sendMessage(ChatColor.RED + "There are no tracked players on the scoreboard"); - } else { - sender.sendMessage(ChatColor.DARK_GREEN + "Showing " + entries.size() + " tracked players on the scoreboard"); - sender.sendMessage(stringCollectionToString(entries)); - } - } else { - String playerName = args[2]; - if (playerName.length() > 16) { - sender.sendMessage(ChatColor.RED + "'" + playerName + "' is too long for a player name"); - return false; - } - Set scores = mainScoreboard.getScores(playerName); - if (scores.isEmpty()) { - sender.sendMessage(ChatColor.RED + "Player " + playerName + " has no scores recorded"); - } else { - sender.sendMessage(ChatColor.DARK_GREEN + "Showing " + scores.size() + " tracked objective(s) for " + playerName); - for (Score score : scores) { - sender.sendMessage("- " + score.getObjective().getDisplayName() + ": " + score.getScore() + " (" + score.getObjective().getName() + ")"); - } - } - } - } - } else if (args[0].equalsIgnoreCase("teams")) { - if (args.length == 1) { - sender.sendMessage(ChatColor.RED + "/scoreboard teams "); - return false; - } - if (args[1].equalsIgnoreCase("list")) { - if (args.length == 2) { - Set teams = mainScoreboard.getTeams(); - if (teams.isEmpty()) { - sender.sendMessage(ChatColor.RED + "There are no teams registered on the scoreboard"); - } else { - sender.sendMessage(ChatColor.DARK_GREEN + "Showing " + teams.size() + " teams on the scoreboard"); - for (Team team : teams) { - sender.sendMessage("- " + team.getName() + ": '" + team.getDisplayName() + "' has " + team.getSize() + " players"); - } - } - } else if (args.length == 3) { - String teamName = args[2]; - Team team = mainScoreboard.getTeam(teamName); - if (team == null) { - sender.sendMessage(ChatColor.RED + "No team was found by the name '" + teamName + "'"); - } else { - Set players = team.getPlayers(); - if (players.isEmpty()) { - sender.sendMessage(ChatColor.RED + "Team " + team.getName() + " has no players"); - } else { - sender.sendMessage(ChatColor.DARK_GREEN + "Showing " + players.size() + " player(s) in team " + team.getName()); - sender.sendMessage(offlinePlayerSetToString(players)); - } - } - } else { - sender.sendMessage(ChatColor.RED + "/scoreboard teams list [name]"); - return false; - } - } else if (args[1].equalsIgnoreCase("add")) { - if (args.length < 3) { - sender.sendMessage(ChatColor.RED + "/scoreboard teams add [display name ...]"); - return false; - } - String name = args[2]; - if (name.length() > 16) { - sender.sendMessage(ChatColor.RED + "The name '" + name + "' is too long for a team, it can be at most 16 characters long"); - } else if (mainScoreboard.getTeam(name) != null) { - sender.sendMessage(ChatColor.RED + "A team with the name '" + name + "' already exists"); - } else { - String displayName = null; - if (args.length > 3) { - displayName = StringUtils.join(ArrayUtils.subarray(args, 3, args.length), ' '); - if (displayName.length() > 32) { - sender.sendMessage(ChatColor.RED + "The display name '" + displayName + "' is too long for a team, it can be at most 32 characters long"); - return false; - } - } - Team team = mainScoreboard.registerNewTeam(name); - if (displayName != null && displayName.length() > 0) { - team.setDisplayName(displayName); - } - sender.sendMessage("Added new team '" + team.getName() + "' successfully"); - } - } else if (args[1].equalsIgnoreCase("remove")) { - if (args.length != 3) { - sender.sendMessage(ChatColor.RED + "/scoreboard teams remove "); - return false; - } - String name = args[2]; - Team team = mainScoreboard.getTeam(name); - if (team == null) { - sender.sendMessage(ChatColor.RED + "No team was found by the name '" + name + "'"); - } else { - team.unregister(); - sender.sendMessage("Removed team " + name); - } - } else if (args[1].equalsIgnoreCase("empty")) { - if (args.length != 3) { - sender.sendMessage(ChatColor.RED + "/scoreboard teams clear "); - return false; - } - String name = args[2]; - Team team = mainScoreboard.getTeam(name); - if (team == null) { - sender.sendMessage(ChatColor.RED + "No team was found by the name '" + name + "'"); - } else { - Set players = team.getPlayers(); - if (players.isEmpty()) { - sender.sendMessage(ChatColor.RED + "Team " + team.getName() + " is already empty, cannot remove nonexistant players"); - } else { - for (OfflinePlayer player : players) { - team.removePlayer(player); - } - sender.sendMessage("Removed all " + players.size() + " player(s) from team " + team.getName()); - } - } - } else if (args[1].equalsIgnoreCase("join")) { - if ((sender instanceof Player) ? args.length < 3 : args.length < 4) { - sender.sendMessage(ChatColor.RED + "/scoreboard teams join [player...]"); - return false; - } - String teamName = args[2]; - Team team = mainScoreboard.getTeam(teamName); - if (team == null) { - sender.sendMessage(ChatColor.RED + "No team was found by the name '" + teamName + "'"); - } else { - Set addedPlayers = new HashSet(); - if ((sender instanceof Player) && args.length == 3) { - team.addPlayer((Player) sender); - addedPlayers.add(sender.getName()); - } else { - for (int i = 3; i < args.length; i++) { - String playerName = args[i]; - OfflinePlayer offlinePlayer; - Player player = Bukkit.getPlayerExact(playerName); - if (player != null) { - offlinePlayer = player; - } else { - offlinePlayer = Bukkit.getOfflinePlayer(playerName); - } - team.addPlayer(offlinePlayer); - addedPlayers.add(offlinePlayer.getName()); - } - } - sender.sendMessage("Added " + addedPlayers.size() + " player(s) to team " + team.getName() + ": " + stringCollectionToString(addedPlayers)); - } - } else if (args[1].equalsIgnoreCase("leave")) { - if (!(sender instanceof Player) && args.length < 3) { - sender.sendMessage(ChatColor.RED + "/scoreboard teams leave [player...]"); - return false; - } - Set left = new HashSet(); - Set noTeam = new HashSet(); - if ((sender instanceof Player) && args.length == 2) { - Team team = mainScoreboard.getPlayerTeam((Player) sender); - if (team != null) { - team.removePlayer((Player) sender); - left.add(sender.getName()); - } else { - noTeam.add(sender.getName()); - } - } else { - for (int i = 2; i < args.length; i++) { - String playerName = args[i]; - OfflinePlayer offlinePlayer; - Player player = Bukkit.getPlayerExact(playerName); - if (player != null) { - offlinePlayer = player; - } else { - offlinePlayer = Bukkit.getOfflinePlayer(playerName); - } - Team team = mainScoreboard.getPlayerTeam(offlinePlayer); - if (team != null) { - team.removePlayer(offlinePlayer); - left.add(offlinePlayer.getName()); - } else { - noTeam.add(offlinePlayer.getName()); - } - } - } - if (!left.isEmpty()) { - sender.sendMessage("Removed " + left.size() + " player(s) from their teams: " + stringCollectionToString(left)); - } - if (!noTeam.isEmpty()) { - sender.sendMessage("Could not remove " + noTeam.size() + " player(s) from their teams: " + stringCollectionToString(noTeam)); - } - } else if (args[1].equalsIgnoreCase("option")) { - if (args.length != 4 && args.length != 5) { - sender.sendMessage(ChatColor.RED + "/scoreboard teams option "); - return false; - } - String teamName = args[2]; - Team team = mainScoreboard.getTeam(teamName); - if (team == null) { - sender.sendMessage(ChatColor.RED + "No team was found by the name '" + teamName + "'"); - return false; - } - String option = args[3].toLowerCase(); - if (!option.equals("friendlyfire") && !option.equals("color") && !option.equals("seefriendlyinvisibles")) { - sender.sendMessage(ChatColor.RED + "/scoreboard teams option "); - return false; - } - if (args.length == 4) { - if (option.equals("color")) { - sender.sendMessage(ChatColor.RED + "Valid values for option color are: " + stringCollectionToString(TEAMS_OPTION_COLOR.keySet())); - } else { - sender.sendMessage(ChatColor.RED + "Valid values for option " + option + " are: true and false"); - } - } else { - String value = args[4].toLowerCase(); - if (option.equals("color")) { - ChatColor color = TEAMS_OPTION_COLOR.get(value); - if (color == null) { - sender.sendMessage(ChatColor.RED + "Valid values for option color are: " + stringCollectionToString(TEAMS_OPTION_COLOR.keySet())); - return false; - } - team.setPrefix(color.toString()); - team.setSuffix(ChatColor.RESET.toString()); - } else { - if (!value.equals("true") && !value.equals("false")) { - sender.sendMessage(ChatColor.RED + "Valid values for option " + option + " are: true and false"); - return false; - } - if (option.equals("friendlyfire")) { - team.setAllowFriendlyFire(value.equals("true")); - } else { - team.setCanSeeFriendlyInvisibles(value.equals("true")); - } - } - sender.sendMessage("Set option " + option + " for team " + team.getName() + " to " + value); - } - } - } else { - sender.sendMessage(ChatColor.RED + "Usage: /scoreboard "); - return false; - } - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length == 1) { - return StringUtil.copyPartialMatches(args[0], MAIN_CHOICES, new ArrayList()); - } - if (args.length > 1) { - if (args[0].equalsIgnoreCase("objectives")) { - if (args.length == 2) { - return StringUtil.copyPartialMatches(args[1], OBJECTIVES_CHOICES, new ArrayList()); - } - if (args[1].equalsIgnoreCase("add")) { - if (args.length == 4) { - return StringUtil.copyPartialMatches(args[3], OBJECTIVES_CRITERIA, new ArrayList()); - } - } else if (args[1].equalsIgnoreCase("remove")) { - if (args.length == 3) { - return StringUtil.copyPartialMatches(args[2], this.getCurrentObjectives(), new ArrayList()); - } - } else if (args[1].equalsIgnoreCase("setdisplay")) { - if (args.length == 3) { - return StringUtil.copyPartialMatches(args[2], OBJECTIVES_DISPLAYSLOT.keySet(), new ArrayList()); - } - if (args.length == 4) { - return StringUtil.copyPartialMatches(args[3], this.getCurrentObjectives(), new ArrayList()); - } - } - } else if (args[0].equalsIgnoreCase("players")) { - if (args.length == 2) { - return StringUtil.copyPartialMatches(args[1], PLAYERS_CHOICES, new ArrayList()); - } - if (args[1].equalsIgnoreCase("set") || args[1].equalsIgnoreCase("add") || args[1].equalsIgnoreCase("remove")) { - if (args.length == 3) { - return super.tabComplete(sender, alias, args); - } - if (args.length == 4) { - return StringUtil.copyPartialMatches(args[3], this.getCurrentObjectives(), new ArrayList()); - } - } else { - if (args.length == 3) { - return StringUtil.copyPartialMatches(args[2], this.getCurrentEntries(), new ArrayList()); - } - } - } else if (args[0].equalsIgnoreCase("teams")) { - if (args.length == 2) { - return StringUtil.copyPartialMatches(args[1], TEAMS_CHOICES, new ArrayList()); - } - if (args[1].equalsIgnoreCase("join")) { - if (args.length == 3) { - return StringUtil.copyPartialMatches(args[2], this.getCurrentTeams(), new ArrayList()); - } - if (args.length >= 4) { - return super.tabComplete(sender, alias, args); - } - } else if (args[1].equalsIgnoreCase("leave")) { - return super.tabComplete(sender, alias, args); - } else if (args[1].equalsIgnoreCase("option")) { - if (args.length == 3) { - return StringUtil.copyPartialMatches(args[2], this.getCurrentTeams(), new ArrayList()); - } - if (args.length == 4) { - return StringUtil.copyPartialMatches(args[3], TEAMS_OPTION_CHOICES, new ArrayList()); - } - if (args.length == 5) { - if (args[3].equalsIgnoreCase("color")) { - return StringUtil.copyPartialMatches(args[4], TEAMS_OPTION_COLOR.keySet(), new ArrayList()); - } else { - return StringUtil.copyPartialMatches(args[4], BOOLEAN, new ArrayList()); - } - } - } else { - if (args.length == 3) { - return StringUtil.copyPartialMatches(args[2], this.getCurrentTeams(), new ArrayList()); - } - } - } - } - - return ImmutableList.of(); - } - - private static String offlinePlayerSetToString(Set set) { - StringBuilder string = new StringBuilder(); - String lastValue = null; - for (OfflinePlayer value : set) { - string.append(lastValue = value.getName()).append(", "); - } - string.delete(string.length() - 2, Integer.MAX_VALUE); - if (string.length() != lastValue.length()) { - string.insert(string.length() - lastValue.length(), "and "); - } - return string.toString(); - - } - - private static String stringCollectionToString(Collection set) { - StringBuilder string = new StringBuilder(); - String lastValue = null; - for (String value : set) { - string.append(lastValue = value).append(", "); - } - string.delete(string.length() - 2, Integer.MAX_VALUE); - if (string.length() != lastValue.length()) { - string.insert(string.length() - lastValue.length(), "and "); - } - return string.toString(); - } - - private List getCurrentObjectives() { - List list = new ArrayList(); - for (Objective objective : Bukkit.getScoreboardManager().getMainScoreboard().getObjectives()) { - list.add(objective.getName()); - } - Collections.sort(list, String.CASE_INSENSITIVE_ORDER); - return list; - } - - private List getCurrentEntries() { - List list = new ArrayList(); - for (String entry : Bukkit.getScoreboardManager().getMainScoreboard().getEntries()) { - list.add(entry); - } - Collections.sort(list, String.CASE_INSENSITIVE_ORDER); - return list; - } - - private List getCurrentTeams() { - List list = new ArrayList(); - for (Team team : Bukkit.getScoreboardManager().getMainScoreboard().getTeams()) { - list.add(team.getName()); - } - Collections.sort(list, String.CASE_INSENSITIVE_ORDER); - return list; - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SeedCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SeedCommand.java deleted file mode 100644 index 3fb0639b2..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SeedCommand.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class SeedCommand extends VanillaCommand { - public SeedCommand() { - super("seed"); - this.description = "Shows the world seed"; - this.usageMessage = "/seed"; - this.setPermission("bukkit.command.seed"); - } - - @Override - public boolean execute(CommandSender sender, String commandLabel, String[] args) { - if (!testPermission(sender)) return true; - long seed; - if (sender instanceof Player) { - seed = ((Player) sender).getWorld().getSeed(); - } else { - seed = Bukkit.getWorlds().get(0).getSeed(); - } - sender.sendMessage("Seed: " + seed); - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SetIdleTimeoutCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SetIdleTimeoutCommand.java deleted file mode 100644 index f6cbe0351..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SetIdleTimeoutCommand.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.bukkit.command.defaults; - -import com.google.common.collect.ImmutableList; - -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; - -import java.util.List; - -@Deprecated -public class SetIdleTimeoutCommand extends VanillaCommand { - - public SetIdleTimeoutCommand() { - super("setidletimeout"); - this.description = "Sets the server's idle timeout"; - this.usageMessage = "/setidletimeout "; - this.setPermission("bukkit.command.setidletimeout"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - - if (args.length == 1) { - int minutes; - - try { - minutes = getInteger(sender, args[0], 0, Integer.MAX_VALUE, true); - } catch (NumberFormatException ex) { - sender.sendMessage(ex.getMessage()); - return true; - } - - Bukkit.getServer().setIdleTimeout(minutes); - - Command.broadcastCommandMessage(sender, "Successfully set the idle timeout to " + minutes + " minutes."); - return true; - } - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SetWorldSpawnCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SetWorldSpawnCommand.java deleted file mode 100644 index 8bec19c95..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SetWorldSpawnCommand.java +++ /dev/null @@ -1,80 +0,0 @@ -package org.bukkit.command.defaults; - -import com.google.common.collect.ImmutableList; -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.List; - -@Deprecated -public class SetWorldSpawnCommand extends VanillaCommand { - - public SetWorldSpawnCommand() { - super("setworldspawn"); - this.description = "Sets a worlds's spawn point. If no coordinates are specified, the player's coordinates will be used."; - this.usageMessage = "/setworldspawn OR /setworldspawn "; - this.setPermission("bukkit.command.setworldspawn"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - - Player player = null; - World world; - if (sender instanceof Player) { - player = (Player) sender; - world = player.getWorld(); - } else { - world = Bukkit.getWorlds().get(0); - } - - final int x, y, z; - - if (args.length == 0) { - if (player == null) { - sender.sendMessage("You can only perform this command as a player"); - return true; - } - - Location location = player.getLocation(); - - x = location.getBlockX(); - y = location.getBlockY(); - z = location.getBlockZ(); - } else if (args.length == 3) { - try { - x = getInteger(sender, args[0], MIN_COORD, MAX_COORD, true); - y = getInteger(sender, args[1], 0, world.getMaxHeight(), true); - z = getInteger(sender, args[2], MIN_COORD, MAX_COORD, true); - } catch (NumberFormatException ex) { - sender.sendMessage(ex.getMessage()); - return true; - } - } else { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - world.setSpawnLocation(x, y, z); - - Command.broadcastCommandMessage(sender, "Set world " + world.getName() + "'s spawnpoint to (" + x + ", " + y + ", " + z + ")"); - return true; - - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SpawnpointCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SpawnpointCommand.java deleted file mode 100644 index be15f7e0b..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SpawnpointCommand.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.bukkit.command.defaults; - -import com.google.common.collect.ImmutableList; -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import java.util.List; - -@Deprecated -public class SpawnpointCommand extends VanillaCommand { - - public SpawnpointCommand() { - super("spawnpoint"); - this.description = "Sets a player's spawn point"; - this.usageMessage = "/spawnpoint OR /spawnpoint OR /spawnpoint "; - this.setPermission("bukkit.command.spawnpoint"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - - Player player; - - if (args.length == 0) { - if (sender instanceof Player) { - player = (Player) sender; - } else { - sender.sendMessage("Please provide a player!"); - return true; - } - } else { - player = Bukkit.getPlayerExact(args[0]); - if (player == null) { - sender.sendMessage("Can't find player " + args[0]); - return true; - } - } - - World world = player.getWorld(); - - if (args.length == 4) { - if (world != null) { - int pos = 1; - final int x, y, z; - try { - x = getInteger(sender, args[pos++], MIN_COORD, MAX_COORD, true); - y = getInteger(sender, args[pos++], 0, world.getMaxHeight()); - z = getInteger(sender, args[pos], MIN_COORD, MAX_COORD, true); - } catch(NumberFormatException ex) { - sender.sendMessage(ex.getMessage()); - return true; - } - - player.setBedSpawnLocation(new Location(world, x, y, z), true); - Command.broadcastCommandMessage(sender, "Set " + player.getDisplayName() + "'s spawnpoint to " + x + ", " + y + ", " + z); - } - } else if (args.length <= 1) { - Location location = player.getLocation(); - player.setBedSpawnLocation(location, true); - Command.broadcastCommandMessage(sender, "Set " + player.getDisplayName() + "'s spawnpoint to " + location.getX() + ", " + location.getY() + ", " + location.getZ()); - } else { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length == 1) { - return super.tabComplete(sender, alias, args); - } - - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SpreadPlayersCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SpreadPlayersCommand.java deleted file mode 100644 index 489f7608f..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/SpreadPlayersCommand.java +++ /dev/null @@ -1,266 +0,0 @@ -package org.bukkit.command.defaults; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Set; - -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.scoreboard.Team; - -@Deprecated -public class SpreadPlayersCommand extends VanillaCommand { - private static final Random random = new Random(); - - public SpreadPlayersCommand() { - super("spreadplayers"); - this.description = "Spreads players around a point"; - this.usageMessage = "/spreadplayers "; - this.setPermission("bukkit.command.spreadplayers"); - } - - @Override - public boolean execute(CommandSender sender, String commandLabel, String[] args) { - if (!testPermission(sender)) { - return true; - } - - if (args.length < 6) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - final double x = getDouble(sender, args[0], -30000000, 30000000); - final double z = getDouble(sender, args[1], -30000000, 30000000); - final double distance = getDouble(sender, args[2]); - final double range = getDouble(sender, args[3]); - - if (distance < 0.0D) { - sender.sendMessage(ChatColor.RED + "Distance is too small."); - return false; - } - - if (range < distance + 1.0D) { - sender.sendMessage(ChatColor.RED + "Max range is too small."); - return false; - } - - final String respectTeams = args[4]; - boolean teams = false; - - if (respectTeams.equalsIgnoreCase("true")) { - teams = true; - } else if (!respectTeams.equalsIgnoreCase("false")) { - sender.sendMessage(String.format(ChatColor.RED + "'%s' is not true or false", args[4])); - return false; - } - - List players = Lists.newArrayList(); - World world = null; - - for (int i = 5; i < args.length; i++) { - Player player = Bukkit.getPlayerExact(args[i]); - if (player == null) { - continue; - } - - if (world == null) { - world = player.getWorld(); - } - players.add(player); - } - - if (world == null) { - return true; - } - - final double xRangeMin = x - range; - final double zRangeMin = z - range; - final double xRangeMax = x + range; - final double zRangeMax = z + range; - - final int spreadSize = teams ? getTeams(players) : players.size(); - - final Location[] locations = getSpreadLocations(world, spreadSize, xRangeMin, zRangeMin, xRangeMax, zRangeMax); - final int rangeSpread = range(world, distance, xRangeMin, zRangeMin, xRangeMax, zRangeMax, locations); - - if (rangeSpread == -1) { - sender.sendMessage(String.format("Could not spread %d %s around %s,%s (too many players for space - try using spread of at most %s)", spreadSize, teams ? "teams" : "players", x, z)); - return false; - } - - final double distanceSpread = spread(world, players, locations, teams); - - sender.sendMessage(String.format("Succesfully spread %d %s around %s,%s", locations.length, teams ? "teams" : "players", x, z)); - if (locations.length > 1) { - sender.sendMessage(String.format("(Average distance between %s is %s blocks apart after %s iterations)", teams ? "teams" : "players", String.format("%.2f", distanceSpread), rangeSpread)); - } - return true; - } - - private int range(World world, double distance, double xRangeMin, double zRangeMin, double xRangeMax, double zRangeMax, Location[] locations) { - boolean flag = true; - double max; - - int i; - - for (i = 0; i < 10000 && flag; ++i) { - flag = false; - max = Float.MAX_VALUE; - - Location loc1; - int j; - - for (int k = 0; k < locations.length; ++k) { - Location loc2 = locations[k]; - - j = 0; - loc1 = new Location(world, 0, 0, 0); - - for (int l = 0; l < locations.length; ++l) { - if (k != l) { - Location loc3 = locations[l]; - double dis = loc2.distanceSquared(loc3); - - max = Math.min(dis, max); - if (dis < distance) { - ++j; - loc1.add(loc3.getX() - loc2.getX(), 0, 0); - loc1.add(loc3.getZ() - loc2.getZ(), 0, 0); - } - } - } - - if (j > 0) { - loc2.setX(loc2.getX() / j); - loc2.setZ(loc2.getZ() / j); - double d7 = Math.sqrt(loc1.getX() * loc1.getX() + loc1.getZ() * loc1.getZ()); - - if (d7 > 0.0D) { - loc1.setX(loc1.getX() / d7); - loc2.add(-loc1.getX(), 0, -loc1.getZ()); - } else { - double x = xRangeMin >= xRangeMax ? xRangeMin : random.nextDouble() * (xRangeMax - xRangeMin) + xRangeMin; - double z = zRangeMin >= zRangeMax ? zRangeMin : random.nextDouble() * (zRangeMax - zRangeMin) + zRangeMin; - loc2.setX(x); - loc2.setZ(z); - } - - flag = true; - } - - boolean swap = false; - - if (loc2.getX() < xRangeMin) { - loc2.setX(xRangeMin); - swap = true; - } else if (loc2.getX() > xRangeMax) { - loc2.setX(xRangeMax); - swap = true; - } - - if (loc2.getZ() < zRangeMin) { - loc2.setZ(zRangeMin); - swap = true; - } else if (loc2.getZ() > zRangeMax) { - loc2.setZ(zRangeMax); - swap = true; - } - if (swap) { - flag = true; - } - } - - if (!flag) { - Location[] locs = locations; - int i1 = locations.length; - - for (j = 0; j < i1; ++j) { - loc1 = locs[j]; - if (world.getHighestBlockYAt(loc1) == 0) { - double x = xRangeMin >= xRangeMax ? xRangeMin : random.nextDouble() * (xRangeMax - xRangeMin) + xRangeMin; - double z = zRangeMin >= zRangeMax ? zRangeMin : random.nextDouble() * (zRangeMax - zRangeMin) + zRangeMin; - locations[i] = (new Location(world, x, 0, z)); - loc1.setX(x); - loc1.setZ(z); - flag = true; - } - } - } - } - - if (i >= 10000) { - return -1; - } else { - return i; - } - } - - private double spread(World world, List list, Location[] locations, boolean teams) { - double distance = 0.0D; - int i = 0; - Map hashmap = Maps.newHashMap(); - - for (int j = 0; j < list.size(); ++j) { - Player player = list.get(j); - Location location; - - if (teams) { - Team team = player.getScoreboard().getPlayerTeam(player); - - if (!hashmap.containsKey(team)) { - hashmap.put(team, locations[i++]); - } - - location = hashmap.get(team); - } else { - location = locations[i++]; - } - - player.teleport(new Location(world, Math.floor(location.getX()) + 0.5D, world.getHighestBlockYAt((int) location.getX(), (int) location.getZ()), Math.floor(location.getZ()) + 0.5D)); - double value = Double.MAX_VALUE; - - for (int k = 0; k < locations.length; ++k) { - if (location != locations[k]) { - double d = location.distanceSquared(locations[k]); - value = Math.min(d, value); - } - } - - distance += value; - } - - distance /= list.size(); - return distance; - } - - private int getTeams(List players) { - Set teams = Sets.newHashSet(); - - for (Player player : players) { - teams.add(player.getScoreboard().getPlayerTeam(player)); - } - - return teams.size(); - } - - private Location[] getSpreadLocations(World world, int size, double xRangeMin, double zRangeMin, double xRangeMax, double zRangeMax) { - Location[] locations = new Location[size]; - - for (int i = 0; i < size; ++i) { - double x = xRangeMin >= xRangeMax ? xRangeMin : random.nextDouble() * (xRangeMax - xRangeMin) + xRangeMin; - double z = zRangeMin >= zRangeMax ? zRangeMin : random.nextDouble() * (zRangeMax - zRangeMin) + zRangeMin; - locations[i] = (new Location(world, x, 0, z)); - } - - return locations; - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/StopCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/StopCommand.java deleted file mode 100644 index a9467e19a..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/StopCommand.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.List; - -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.Validate; - -import org.bukkit.Bukkit; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class StopCommand extends VanillaCommand { - public StopCommand() { - super("stop"); - this.description = "Stops the server with optional reason"; - this.usageMessage = "/stop [reason]"; - this.setPermission("bukkit.command.stop"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - - Command.broadcastCommandMessage(sender, "Stopping the server.."); - Bukkit.shutdown(); - - String reason = this.createString(args, 0); - if (StringUtils.isNotEmpty(reason)) { - for (Player player : Bukkit.getOnlinePlayers()) { - player.kickPlayer(reason); - } - } - - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/TeleportCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/TeleportCommand.java deleted file mode 100644 index 7460196e5..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/TeleportCommand.java +++ /dev/null @@ -1,125 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Location; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class TeleportCommand extends VanillaCommand { - - public TeleportCommand() { - super("tp"); - this.description = "Teleports the given player (or yourself) to another player or coordinates"; - this.usageMessage = "/tp [player] and/or "; - this.setPermission("bukkit.command.teleport"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - if (args.length < 1 || args.length > 4) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - Player player; - - if (args.length == 1 || args.length == 3) { - if (sender instanceof Player) { - player = (Player) sender; - } else { - sender.sendMessage("Please provide a player!"); - return true; - } - } else { - player = Bukkit.getPlayerExact(args[0]); - } - - if (player == null) { - sender.sendMessage("Player not found: " + args[0]); - return true; - } - - if (args.length < 3) { - Player target = Bukkit.getPlayerExact(args[args.length - 1]); - if (target == null) { - sender.sendMessage("Can't find player " + args[args.length - 1] + ". No tp."); - return true; - } - player.teleport(target, TeleportCause.COMMAND); - Command.broadcastCommandMessage(sender, "Teleported " + player.getDisplayName() + " to " + target.getDisplayName()); - } else if (player.getWorld() != null) { - Location playerLocation = player.getLocation(); - double x = getCoordinate(sender, playerLocation.getX(), args[args.length - 3]); - double y = getCoordinate(sender, playerLocation.getY(), args[args.length - 2], 0, 0); - double z = getCoordinate(sender, playerLocation.getZ(), args[args.length - 1]); - - if (x == MIN_COORD_MINUS_ONE || y == MIN_COORD_MINUS_ONE || z == MIN_COORD_MINUS_ONE) { - sender.sendMessage("Please provide a valid location!"); - return true; - } - - playerLocation.setX(x); - playerLocation.setY(y); - playerLocation.setZ(z); - - player.teleport(playerLocation, TeleportCause.COMMAND); - Command.broadcastCommandMessage(sender, String.format("Teleported %s to %.2f, %.2f, %.2f", player.getDisplayName(), x, y, z)); - } - return true; - } - - private double getCoordinate(CommandSender sender, double current, String input) { - return getCoordinate(sender, current, input, MIN_COORD, MAX_COORD); - } - - private double getCoordinate(CommandSender sender, double current, String input, int min, int max) { - boolean relative = input.startsWith("~"); - double result = relative ? current : 0; - - if (!relative || input.length() > 1) { - boolean exact = input.contains("."); - if (relative) input = input.substring(1); - - double testResult = getDouble(sender, input); - if (testResult == MIN_COORD_MINUS_ONE) { - return MIN_COORD_MINUS_ONE; - } - result += testResult; - - if (!exact && !relative) result += 0.5f; - } - if (min != 0 || max != 0) { - if (result < min) { - result = MIN_COORD_MINUS_ONE; - } - - if (result > max) { - result = MIN_COORD_MINUS_ONE; - } - } - - return result; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length == 1 || args.length == 2) { - return super.tabComplete(sender, alias, args); - } - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/TellCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/TellCommand.java deleted file mode 100644 index 2e5d811d4..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/TellCommand.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.Arrays; - -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -@Deprecated -public class TellCommand extends VanillaCommand { - public TellCommand() { - super("tell"); - this.description = "Sends a private message to the given player"; - this.usageMessage = "/tell "; - this.setAliases(Arrays.asList(new String[] { "w", "msg" })); - this.setPermission("bukkit.command.tell"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - if (args.length < 2) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - Player player = Bukkit.getPlayerExact(args[0]); - - // If a player is hidden from the sender pretend they are offline - if (player == null || (sender instanceof Player && !((Player) sender).canSee(player))) { - sender.sendMessage("There's no player by that name online."); - } else { - StringBuilder message = new StringBuilder(); - - for (int i = 1; i < args.length; i++) { - if (i > 1) message.append(" "); - message.append(args[i]); - } - - String result = ChatColor.GRAY + sender.getName() + " whispers " + message; - - sender.sendMessage("[" + sender.getName() + "->" + player.getName() + "] " + message); - player.sendMessage(result); - } - - return true; - } - - // Spigot Start - @Override - public java.util.List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException - { - if ( args.length == 0 ) - { - return super.tabComplete( sender, alias, args ); - } - return java.util.Collections.emptyList(); - } - // Spigot End -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/TestForCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/TestForCommand.java deleted file mode 100644 index b5758a97f..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/TestForCommand.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.bukkit.command.defaults; - -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; - -@Deprecated -public class TestForCommand extends VanillaCommand { - public TestForCommand() { - super("testfor"); - this.description = "Tests whether a specifed player is online"; - this.usageMessage = "/testfor "; - this.setPermission("bukkit.command.testfor"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - if (args.length < 1) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - sender.sendMessage(ChatColor.RED + "/testfor is only usable by commandblocks with analog output."); - return true; - } - - // Spigot Start - @Override - public java.util.List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException - { - if ( args.length == 0 ) - { - return super.tabComplete( sender, alias, args ); - } - return java.util.Collections.emptyList(); - } - // Spigot End -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/TimeCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/TimeCommand.java deleted file mode 100644 index edce68a25..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/TimeCommand.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.World; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.util.StringUtil; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class TimeCommand extends VanillaCommand { - private static final List TABCOMPLETE_ADD_SET = ImmutableList.of("add", "set"); - private static final List TABCOMPLETE_DAY_NIGHT = ImmutableList.of("day", "night"); - - public TimeCommand() { - super("time"); - this.description = "Changes the time on each world"; - this.usageMessage = "/time set \n/time add "; - this.setPermission("bukkit.command.time.add;bukkit.command.time.set"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (args.length < 2) { - sender.sendMessage(ChatColor.RED + "Incorrect usage. Correct usage:\n" + usageMessage); - return false; - } - - int value; - - if (args[0].equals("set")) { - if (!sender.hasPermission("bukkit.command.time.set")) { - sender.sendMessage(ChatColor.RED + "You don't have permission to set the time"); - return true; - } - - if (args[1].equals("day")) { - value = 0; - } else if (args[1].equals("night")) { - value = 12500; - } else { - value = getInteger(sender, args[1], 0); - } - - for (World world : Bukkit.getWorlds()) { - world.setTime(value); - } - - Command.broadcastCommandMessage(sender, "Set time to " + value); - } else if (args[0].equals("add")) { - if (!sender.hasPermission("bukkit.command.time.add")) { - sender.sendMessage(ChatColor.RED + "You don't have permission to set the time"); - return true; - } - - value = getInteger(sender, args[1], 0); - - for (World world : Bukkit.getWorlds()) { - world.setFullTime(world.getFullTime() + value); - } - - Command.broadcastCommandMessage(sender, "Added " + value + " to time"); - } else { - sender.sendMessage("Unknown method. Usage: " + usageMessage); - } - - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length == 1) { - return StringUtil.copyPartialMatches(args[0], TABCOMPLETE_ADD_SET, new ArrayList(TABCOMPLETE_ADD_SET.size())); - } else if (args.length == 2 && args[0].equalsIgnoreCase("set")) { - return StringUtil.copyPartialMatches(args[1], TABCOMPLETE_DAY_NIGHT, new ArrayList(TABCOMPLETE_DAY_NIGHT.size())); - } - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/ToggleDownfallCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/ToggleDownfallCommand.java deleted file mode 100644 index 91268a6fd..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/ToggleDownfallCommand.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.World; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class ToggleDownfallCommand extends VanillaCommand { - public ToggleDownfallCommand() { - super("toggledownfall"); - this.description = "Toggles rain on/off on a given world"; - this.usageMessage = "/toggledownfall"; - this.setPermission("bukkit.command.toggledownfall"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - - World world = null; - - if (args.length == 1) { - world = Bukkit.getWorld(args[0]); - - if (world == null) { - sender.sendMessage(ChatColor.RED + "No world exists with the name '" + args[0] + "'"); - return true; - } - } else if (sender instanceof Player) { - world = ((Player) sender).getWorld(); - } else { - world = Bukkit.getWorlds().get(0); - } - - Command.broadcastCommandMessage(sender, "Toggling downfall " + (world.hasStorm() ? "off" : "on") + " for world '" + world.getName() + "'"); - world.setStorm(!world.hasStorm()); - - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/WeatherCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/WeatherCommand.java deleted file mode 100644 index b86a50830..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/WeatherCommand.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.bukkit.command.defaults; - -import com.google.common.collect.ImmutableList; -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.World; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.util.StringUtil; - -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -@Deprecated -public class WeatherCommand extends VanillaCommand { - private static final List WEATHER_TYPES = ImmutableList.of("clear", "rain", "thunder"); - - public WeatherCommand() { - super("weather"); - this.description = "Changes the weather"; - this.usageMessage = "/weather [duration in seconds]"; - this.setPermission("bukkit.command.weather"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - if (args.length == 0) { - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } - - int duration = (300 + new Random().nextInt(600)) * 20; - if (args.length >= 2) { - duration = getInteger(sender, args[1], 1, 1000000) * 20; - } - - World world = Bukkit.getWorlds().get(0); - - world.setWeatherDuration(duration); - world.setThunderDuration(duration); - - if ("clear".equalsIgnoreCase(args[0])) { - world.setStorm(false); - world.setThundering(false); - Command.broadcastCommandMessage(sender, "Changed weather to clear for " + (duration / 20) + " seconds."); - } else if ("rain".equalsIgnoreCase(args[0])) { - world.setStorm(true); - world.setThundering(false); - Command.broadcastCommandMessage(sender, "Changed weather to rainy for " + (duration / 20) + " seconds."); - } else if ("thunder".equalsIgnoreCase(args[0])) { - world.setStorm(true); - world.setThundering(true); - Command.broadcastCommandMessage(sender, "Changed weather to thundering " + (duration / 20) + " seconds."); - } - - return true; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length == 1) { - return StringUtil.copyPartialMatches(args[0], WEATHER_TYPES, new ArrayList(WEATHER_TYPES.size())); - } - - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/WhitelistCommand.java b/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/WhitelistCommand.java deleted file mode 100644 index 855f5600f..000000000 --- a/NachoSpigot-API/src/main/java/org/bukkit/command/defaults/WhitelistCommand.java +++ /dev/null @@ -1,128 +0,0 @@ -package org.bukkit.command.defaults; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.util.StringUtil; - -import com.google.common.collect.ImmutableList; - -@Deprecated -public class WhitelistCommand extends VanillaCommand { - private static final List WHITELIST_SUBCOMMANDS = ImmutableList.of("add", "remove", "on", "off", "list", "reload"); - - public WhitelistCommand() { - super("whitelist"); - this.description = "Manages the list of players allowed to use this server"; - this.usageMessage = "/whitelist (add|remove) \n/whitelist (on|off|list|reload)"; - this.setPermission("bukkit.command.whitelist.reload;bukkit.command.whitelist.enable;bukkit.command.whitelist.disable;bukkit.command.whitelist.list;bukkit.command.whitelist.add;bukkit.command.whitelist.remove"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - - if (args.length == 1) { - if (args[0].equalsIgnoreCase("reload")) { - if (badPerm(sender, "reload")) return true; - - Bukkit.reloadWhitelist(); - Command.broadcastCommandMessage(sender, "Reloaded white-list from file"); - return true; - } else if (args[0].equalsIgnoreCase("on")) { - if (badPerm(sender, "enable")) return true; - - Bukkit.setWhitelist(true); - Command.broadcastCommandMessage(sender, "Turned on white-listing"); - return true; - } else if (args[0].equalsIgnoreCase("off")) { - if (badPerm(sender, "disable")) return true; - - Bukkit.setWhitelist(false); - Command.broadcastCommandMessage(sender, "Turned off white-listing"); - return true; - } else if (args[0].equalsIgnoreCase("list")) { - if (badPerm(sender, "list")) return true; - - StringBuilder result = new StringBuilder(); - - for (OfflinePlayer player : Bukkit.getWhitelistedPlayers()) { - if (result.length() > 0) { - result.append(", "); - } - - result.append(player.getName()); - } - - sender.sendMessage("White-listed players: " + result.toString()); - return true; - } - } else if (args.length == 2) { - if (args[0].equalsIgnoreCase("add")) { - if (badPerm(sender, "add")) return true; - - Bukkit.getOfflinePlayer(args[1]).setWhitelisted(true); - - Command.broadcastCommandMessage(sender, "Added " + args[1] + " to white-list"); - return true; - } else if (args[0].equalsIgnoreCase("remove")) { - if (badPerm(sender, "remove")) return true; - - Bukkit.getOfflinePlayer(args[1]).setWhitelisted(false); - - Command.broadcastCommandMessage(sender, "Removed " + args[1] + " from white-list"); - return true; - } - } - - sender.sendMessage(ChatColor.RED + "Correct command usage:\n" + usageMessage); - return false; - } - - private boolean badPerm(CommandSender sender, String perm) { - if (!sender.hasPermission("bukkit.command.whitelist." + perm)) { - sender.sendMessage(ChatColor.RED + "You do not have permission to perform this action."); - return true; - } - - return false; - } - - @Override - public List tabComplete(CommandSender sender, String alias, String[] args) { - Validate.notNull(sender, "Sender cannot be null"); - Validate.notNull(args, "Arguments cannot be null"); - Validate.notNull(alias, "Alias cannot be null"); - - if (args.length == 1) { - return StringUtil.copyPartialMatches(args[0], WHITELIST_SUBCOMMANDS, new ArrayList(WHITELIST_SUBCOMMANDS.size())); - } else if (args.length == 2) { - if (args[0].equalsIgnoreCase("add")) { - List completions = new ArrayList(); - for (OfflinePlayer player : Bukkit.getOnlinePlayers()) { // Spigot - well maybe sometimes you haven't turned the whitelist on just yet. - String name = player.getName(); - if (StringUtil.startsWithIgnoreCase(name, args[1]) && !player.isWhitelisted()) { - completions.add(name); - } - } - return completions; - } else if (args[0].equalsIgnoreCase("remove")) { - List completions = new ArrayList(); - for (OfflinePlayer player : Bukkit.getWhitelistedPlayers()) { - String name = player.getName(); - if (StringUtil.startsWithIgnoreCase(name, args[1])) { - completions.add(name); - } - } - return completions; - } - } - return ImmutableList.of(); - } -} diff --git a/NachoSpigot-API/src/main/java/org/bukkit/enchantments/Enchantment.java b/NachoSpigot-API/src/main/java/org/bukkit/enchantments/Enchantment.java index c82d67998..d193444da 100644 --- a/NachoSpigot-API/src/main/java/org/bukkit/enchantments/Enchantment.java +++ b/NachoSpigot-API/src/main/java/org/bukkit/enchantments/Enchantment.java @@ -3,7 +3,6 @@ import java.util.HashMap; import java.util.Map; -import org.bukkit.command.defaults.EnchantCommand; import org.bukkit.inventory.ItemStack; /** @@ -261,7 +260,6 @@ public static boolean isAcceptingRegistrations() { */ public static void stopAcceptingRegistrations() { acceptingNew = false; - EnchantCommand.buildEnchantments(); } /** From c3513a7ec40be539bf3824a3aeb839552a78c057 Mon Sep 17 00:00:00 2001 From: crafter23456 <64259198+crafter23456@users.noreply.github.com> Date: Fri, 8 Apr 2022 17:15:44 +0200 Subject: [PATCH 2/2] adding these back --- .../java/com/google/common/base/Objects.java | 451 +++++ .../common/util/concurrent/Futures.java | 1670 +++++++++++++++++ .../common/util/concurrent/MoreExecutors.java | 1172 ++++++++++++ 3 files changed, 3293 insertions(+) create mode 100644 NachoSpigot-API/src/main/java/com/google/common/base/Objects.java create mode 100644 NachoSpigot-API/src/main/java/com/google/common/util/concurrent/Futures.java create mode 100644 NachoSpigot-API/src/main/java/com/google/common/util/concurrent/MoreExecutors.java diff --git a/NachoSpigot-API/src/main/java/com/google/common/base/Objects.java b/NachoSpigot-API/src/main/java/com/google/common/base/Objects.java new file mode 100644 index 000000000..0101907a6 --- /dev/null +++ b/NachoSpigot-API/src/main/java/com/google/common/base/Objects.java @@ -0,0 +1,451 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.common.base; + +import com.google.common.annotations.GwtCompatible; + +import javax.annotation.CheckReturnValue; +import javax.annotation.Nullable; +import java.util.Arrays; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Helper functions that can operate on any {@code Object}. + * + *

See the Guava User Guide on writing + * {@code Object} methods with {@code Objects}. + * + * @author Laurence Gonsalves + * @since 2.0 (imported from Google Collections Library) + */ +@GwtCompatible +public final class Objects { + private Objects() {} + + /** + * Determines whether two possibly-null objects are equal. Returns: + * + *

    + *
  • {@code true} if {@code a} and {@code b} are both null. + *
  • {@code true} if {@code a} and {@code b} are both non-null and they are + * equal according to {@link Object#equals(Object)}. + *
  • {@code false} in all other situations. + *
+ * + *

This assumes that any non-null objects passed to this function conform + * to the {@code equals()} contract. + */ + @CheckReturnValue + public static boolean equal(@Nullable Object a, @Nullable Object b) { + return java.util.Objects.equals(a, b); // Nacho + } + + /** + * Generates a hash code for multiple values. The hash code is generated by + * calling {@link Arrays#hashCode(Object[])}. Note that array arguments to + * this method, with the exception of a single Object array, do not get any + * special handling; their hash codes are based on identity and not contents. + * + *

This is useful for implementing {@link Object#hashCode()}. For example, + * in an object that has three properties, {@code x}, {@code y}, and + * {@code z}, one could write: + *

   {@code
+     *   public int hashCode() {
+     *     return Objects.hashCode(getX(), getY(), getZ());
+     *   }}
+ * + *

Warning: When a single object is supplied, the returned hash code + * does not equal the hash code of that object. + */ + public static int hashCode(@Nullable Object... objects) { + return Arrays.hashCode(objects); + } + + // Nacho start + /** + * Creates an instance of {@link ToStringHelper}. + * + *

This is helpful for implementing {@link Object#toString()}. + * Specification by example:

   {@code
+     *   // Returns "ClassName{}"
+     *   Objects.toStringHelper(this)
+     *       .toString();
+     *
+     *   // Returns "ClassName{x=1}"
+     *   Objects.toStringHelper(this)
+     *       .add("x", 1)
+     *       .toString();
+     *
+     *   // Returns "MyObject{x=1}"
+     *   Objects.toStringHelper("MyObject")
+     *       .add("x", 1)
+     *       .toString();
+     *
+     *   // Returns "ClassName{x=1, y=foo}"
+     *   Objects.toStringHelper(this)
+     *       .add("x", 1)
+     *       .add("y", "foo")
+     *       .toString();
+     *
+     *   // Returns "ClassName{x=1}"
+     *   Objects.toStringHelper(this)
+     *       .omitNullValues()
+     *       .add("x", 1)
+     *       .add("y", null)
+     *       .toString();
+     *   }}
+ * + *

Note that in GWT, class names are often obfuscated. + * + * @param self the object to generate the string for (typically {@code this}), + * used only for its class name + * @since 2.0 + * @deprecated replaced by {@link MoreObjects#toStringHelper(Object)} + * @see MoreObjects#toStringHelper(Object) + */ + @Deprecated + public static ToStringHelper toStringHelper(Object self) { + return new ToStringHelper(simpleName(self.getClass())); + } + + /** + * Creates an instance of {@link ToStringHelper} in the same manner as + * {@link Objects#toStringHelper(Object)}, but using the name of {@code clazz} + * instead of using an instance's {@link Object#getClass()}. + * + *

Note that in GWT, class names are often obfuscated. + * + * @param clazz the {@link Class} of the instance + * @since 7.0 (source-compatible since 2.0) + * @deprecated replaced by {@link MoreObjects#toStringHelper(Class)} + * @see MoreObjects#toStringHelper(Class) + */ + @Deprecated + public static ToStringHelper toStringHelper(Class clazz) { + return new ToStringHelper(simpleName(clazz)); + } + + /** + * Creates an instance of {@link ToStringHelper} in the same manner as + * {@link Objects#toStringHelper(Object)}, but using {@code className} instead + * of using an instance's {@link Object#getClass()}. + * + * @param className the name of the instance type + * @since 7.0 (source-compatible since 2.0) + * @deprecated replaced by {@link MoreObjects#toStringHelper(String)} + * @see MoreObjects#toStringHelper(String) + */ + @Deprecated + public static ToStringHelper toStringHelper(String className) { + return new ToStringHelper(className); + } + + /** + * {@link Class#getSimpleName()} is not GWT compatible yet, so we + * provide our own implementation. + * @deprecated {@link Class#getSimpleName()} is now GWT compatible, use it instead + * @see Class#getSimpleName() + */ + @Deprecated + private static String simpleName(Class clazz) { + String name = clazz.getName(); + + // the nth anonymous class has a class name ending in "Outer$n" + // and local inner classes have names ending in "Outer.$1Inner" + name = name.replaceAll("\\$[0-9]+", "\\$"); + + // we want the name of the inner class all by its lonesome + int start = name.lastIndexOf('$'); + + // if this isn't an inner class, just find the start of the + // top level class name. + if (start == -1) { + start = name.lastIndexOf('.'); + } + return name.substring(start + 1); + } + + /** + * Returns the first of two given parameters that is not {@code null}, if + * either is, or otherwise throws a {@link NullPointerException}. + * + *

Note: if {@code first} is represented as an {@link Optional}, + * this can be accomplished with + * {@linkplain Optional#or(Object) first.or(second)}. + * That approach also allows for lazy evaluation of the fallback instance, + * using {@linkplain Optional#or(Supplier) first.or(Supplier)}. + * + * @return {@code first} if {@code first} is not {@code null}, or + * {@code second} if {@code first} is {@code null} and {@code second} is + * not {@code null} + * @throws NullPointerException if both {@code first} and {@code second} were + * {@code null} + * @since 3.0 + * @deprecated replaced by {@link MoreObjects#firstNonNull(Object, Object)} + * @see MoreObjects#firstNonNull(Object, Object) + */ + @Deprecated + public static T firstNonNull(@Nullable T first, @Nullable T second) { + return first != null ? first : checkNotNull(second); + } + + /** + * Support class for {@link Objects#toStringHelper}. + * + * @author Jason Lee + * @since 2.0 + * @deprecated replaced by {@link MoreObjects.ToStringHelper} + * @see MoreObjects.ToStringHelper + */ + @Deprecated + public static final class ToStringHelper { + private final String className; + private ValueHolder holderHead = new ValueHolder(); + private ValueHolder holderTail = holderHead; + private boolean omitNullValues = false; + + /** + * Use {@link Objects#toStringHelper(Object)} to create an instance. + */ + private ToStringHelper(String className) { + this.className = checkNotNull(className); + } + + /** + * Configures the {@link ToStringHelper} so {@link #toString()} will ignore + * properties with null value. The order of calling this method, relative + * to the {@code add()}/{@code addValue()} methods, is not significant. + * + * @since 12.0 + */ + public ToStringHelper omitNullValues() { + omitNullValues = true; + return this; + } + + /** + * Adds a name/value pair to the formatted output in {@code name=value} + * format. If {@code value} is {@code null}, the string {@code "null"} + * is used, unless {@link #omitNullValues()} is called, in which case this + * name/value pair will not be added. + */ + public ToStringHelper add(String name, @Nullable Object value) { + return addHolder(name, value); + } + + /** + * Adds a name/value pair to the formatted output in {@code name=value} + * format. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper add(String name, boolean value) { + return addHolder(name, String.valueOf(value)); + } + + /** + * Adds a name/value pair to the formatted output in {@code name=value} + * format. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper add(String name, char value) { + return addHolder(name, String.valueOf(value)); + } + + /** + * Adds a name/value pair to the formatted output in {@code name=value} + * format. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper add(String name, double value) { + return addHolder(name, String.valueOf(value)); + } + + /** + * Adds a name/value pair to the formatted output in {@code name=value} + * format. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper add(String name, float value) { + return addHolder(name, String.valueOf(value)); + } + + /** + * Adds a name/value pair to the formatted output in {@code name=value} + * format. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper add(String name, int value) { + return addHolder(name, String.valueOf(value)); + } + + /** + * Adds a name/value pair to the formatted output in {@code name=value} + * format. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper add(String name, long value) { + return addHolder(name, String.valueOf(value)); + } + + /** + * Adds an unnamed value to the formatted output. + * + *

It is strongly encouraged to use {@link #add(String, Object)} instead + * and give value a readable name. + */ + public ToStringHelper addValue(@Nullable Object value) { + return addHolder(value); + } + + /** + * Adds an unnamed value to the formatted output. + * + *

It is strongly encouraged to use {@link #add(String, boolean)} instead + * and give value a readable name. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper addValue(boolean value) { + return addHolder(String.valueOf(value)); + } + + /** + * Adds an unnamed value to the formatted output. + * + *

It is strongly encouraged to use {@link #add(String, char)} instead + * and give value a readable name. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper addValue(char value) { + return addHolder(String.valueOf(value)); + } + + /** + * Adds an unnamed value to the formatted output. + * + *

It is strongly encouraged to use {@link #add(String, double)} instead + * and give value a readable name. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper addValue(double value) { + return addHolder(String.valueOf(value)); + } + + /** + * Adds an unnamed value to the formatted output. + * + *

It is strongly encouraged to use {@link #add(String, float)} instead + * and give value a readable name. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper addValue(float value) { + return addHolder(String.valueOf(value)); + } + + /** + * Adds an unnamed value to the formatted output. + * + *

It is strongly encouraged to use {@link #add(String, int)} instead + * and give value a readable name. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper addValue(int value) { + return addHolder(String.valueOf(value)); + } + + /** + * Adds an unnamed value to the formatted output. + * + *

It is strongly encouraged to use {@link #add(String, long)} instead + * and give value a readable name. + * + * @since 11.0 (source-compatible since 2.0) + */ + public ToStringHelper addValue(long value) { + return addHolder(String.valueOf(value)); + } + + /** + * Returns a string in the format specified by {@link + * Objects#toStringHelper(Object)}. + * + *

After calling this method, you can keep adding more properties to later + * call toString() again and get a more complete representation of the + * same object; but properties cannot be removed, so this only allows + * limited reuse of the helper instance. The helper allows duplication of + * properties (multiple name/value pairs with the same name can be added). + */ + @Override public String toString() { + // create a copy to keep it consistent in case value changes + boolean omitNullValuesSnapshot = omitNullValues; + String nextSeparator = ""; + StringBuilder builder = new StringBuilder(32).append(className) + .append('{'); + for (ValueHolder valueHolder = holderHead.next; valueHolder != null; + valueHolder = valueHolder.next) { + if (!omitNullValuesSnapshot || valueHolder.value != null) { + builder.append(nextSeparator); + nextSeparator = ", "; + + if (valueHolder.name != null) { + builder.append(valueHolder.name).append('='); + } + builder.append(valueHolder.value); + } + } + return builder.append('}').toString(); + } + + private ValueHolder addHolder() { + ValueHolder valueHolder = new ValueHolder(); + holderTail = holderTail.next = valueHolder; + return valueHolder; + } + + private ToStringHelper addHolder(@Nullable Object value) { + ValueHolder valueHolder = addHolder(); + valueHolder.value = value; + return this; + } + + private ToStringHelper addHolder(String name, @Nullable Object value) { + ValueHolder valueHolder = addHolder(); + valueHolder.value = value; + valueHolder.name = checkNotNull(name); + return this; + } + + private static final class ValueHolder { + String name; + Object value; + ValueHolder next; + } + } + // Nacho end +} \ No newline at end of file diff --git a/NachoSpigot-API/src/main/java/com/google/common/util/concurrent/Futures.java b/NachoSpigot-API/src/main/java/com/google/common/util/concurrent/Futures.java new file mode 100644 index 000000000..03dc028d9 --- /dev/null +++ b/NachoSpigot-API/src/main/java/com/google/common/util/concurrent/Futures.java @@ -0,0 +1,1670 @@ +/* + * Copyright (C) 2006 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.common.util.concurrent; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.util.concurrent.Internal.toNanosSaturated; +import static com.google.common.util.concurrent.MoreExecutors.directExecutor; +import static com.google.common.util.concurrent.Uninterruptibles.getUninterruptibly; +import static java.util.Objects.requireNonNull; + +import com.google.common.annotations.Beta; +import com.google.common.annotations.GwtCompatible; +import com.google.common.annotations.GwtIncompatible; +import com.google.common.base.Function; +import com.google.common.base.MoreObjects; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import com.google.common.util.concurrent.CollectionFuture.ListFuture; +import com.google.common.util.concurrent.ImmediateFuture.ImmediateCancelledFuture; +import com.google.common.util.concurrent.ImmediateFuture.ImmediateFailedFuture; +import com.google.common.util.concurrent.internal.InternalFutureFailureAccess; +import com.google.common.util.concurrent.internal.InternalFutures; +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import java.time.Duration; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; +import javax.annotation.CheckForNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * Static utility methods pertaining to the {@link Future} interface. + * + *

Many of these methods use the {@link ListenableFuture} API; consult the Guava User Guide + * article on {@code + * ListenableFuture}. + * + *

The main purpose of {@code ListenableFuture} is to help you chain together a graph of + * asynchronous operations. You can chain them together manually with calls to methods like {@link + * Futures#transform(ListenableFuture, Function, Executor) Futures.transform}, but you will often + * find it easier to use a framework. Frameworks automate the process, often adding features like + * monitoring, debugging, and cancellation. Examples of frameworks include: + * + *

+ * + *

If you do chain your operations manually, you may want to use {@link FluentFuture}. + * + * @author Kevin Bourrillion + * @author Nishant Thakkar + * @author Sven Mawson + * @since 1.0 + */ +@GwtCompatible(emulated = true) +@ElementTypesAreNonnullByDefault +public final class Futures extends GwtFuturesCatchingSpecialization { + + // A note on memory visibility. + // Many of the utilities in this class (transform, withFallback, withTimeout, asList, combine) + // have two requirements that significantly complicate their design. + // 1. Cancellation should propagate from the returned future to the input future(s). + // 2. The returned futures shouldn't unnecessarily 'pin' their inputs after completion. + // + // A consequence of these requirements is that the delegate futures cannot be stored in + // final fields. + // + // For simplicity the rest of this description will discuss Futures.catching since it is the + // simplest instance, though very similar descriptions apply to many other classes in this file. + // + // In the constructor of AbstractCatchingFuture, the delegate future is assigned to a field + // 'inputFuture'. That field is non-final and non-volatile. There are 2 places where the + // 'inputFuture' field is read and where we will have to consider visibility of the write + // operation in the constructor. + // + // 1. In the listener that performs the callback. In this case it is fine since inputFuture is + // assigned prior to calling addListener, and addListener happens-before any invocation of the + // listener. Notably, this means that 'volatile' is unnecessary to make 'inputFuture' visible + // to the listener. + // + // 2. In done() where we may propagate cancellation to the input. In this case it is _not_ fine. + // There is currently nothing that enforces that the write to inputFuture in the constructor is + // visible to done(). This is because there is no happens before edge between the write and a + // (hypothetical) unsafe read by our caller. Note: adding 'volatile' does not fix this issue, + // it would just add an edge such that if done() observed non-null, then it would also + // definitely observe all earlier writes, but we still have no guarantee that done() would see + // the inital write (just stronger guarantees if it does). + // + // See: http://cs.oswego.edu/pipermail/concurrency-interest/2015-January/013800.html + // For a (long) discussion about this specific issue and the general futility of life. + // + // For the time being we are OK with the problem discussed above since it requires a caller to + // introduce a very specific kind of data-race. And given the other operations performed by these + // methods that involve volatile read/write operations, in practice there is no issue. Also, the + // way in such a visibility issue would surface is most likely as a failure of cancel() to + // propagate to the input. Cancellation propagation is fundamentally racy so this is fine. + // + // Future versions of the JMM may revise safe construction semantics in such a way that we can + // safely publish these objects and we won't need this whole discussion. + // TODO(user,lukes): consider adding volatile to all these fields since in current known JVMs + // that should resolve the issue. This comes at the cost of adding more write barriers to the + // implementations. + + private Futures() {} + + /** + * Creates a {@code ListenableFuture} which has its value set immediately upon construction. The + * getters just return the value. This {@code Future} can't be canceled or timed out and its + * {@code isDone()} method always returns {@code true}. + */ + public static ListenableFuture immediateFuture( + @ParametricNullness V value) { + if (value == null) { + // This cast is safe because null is assignable to V for all V (i.e. it is bivariant) + @SuppressWarnings("unchecked") + ListenableFuture typedNull = (ListenableFuture) ImmediateFuture.NULL; + return typedNull; + } + return new ImmediateFuture<>(value); + } + + /** + * Returns a successful {@code ListenableFuture}. This method is equivalent to {@code + * immediateFuture(null)} except that it is restricted to produce futures of type {@code Void}. + * + * @since 29.0 + */ + @SuppressWarnings("unchecked") + public static ListenableFuture<@Nullable Void> immediateVoidFuture() { + return (ListenableFuture<@Nullable Void>) ImmediateFuture.NULL; + } + + /** + * Returns a {@code ListenableFuture} which has an exception set immediately upon construction. + * + *

The returned {@code Future} can't be cancelled, and its {@code isDone()} method always + * returns {@code true}. Calling {@code get()} will immediately throw the provided {@code + * Throwable} wrapped in an {@code ExecutionException}. + */ + public static ListenableFuture immediateFailedFuture( + Throwable throwable) { + checkNotNull(throwable); + return new ImmediateFailedFuture(throwable); + } + + /** + * Creates a {@code ListenableFuture} which is cancelled immediately upon construction, so that + * {@code isCancelled()} always returns {@code true}. + * + * @since 14.0 + */ + public static ListenableFuture immediateCancelledFuture() { + return new ImmediateCancelledFuture(); + } + + /** + * Executes {@code callable} on the specified {@code executor}, returning a {@code Future}. + * + * @throws RejectedExecutionException if the task cannot be scheduled for execution + * @since 28.2 + */ + public static ListenableFuture submit( + Callable callable, Executor executor) { + TrustedListenableFutureTask task = TrustedListenableFutureTask.create(callable); + executor.execute(task); + return task; + } + + /** + * Executes {@code runnable} on the specified {@code executor}, returning a {@code Future} that + * will complete after execution. + * + * @throws RejectedExecutionException if the task cannot be scheduled for execution + * @since 28.2 + */ + public static ListenableFuture<@Nullable Void> submit(Runnable runnable, Executor executor) { + TrustedListenableFutureTask<@Nullable Void> task = + TrustedListenableFutureTask.create(runnable, null); + executor.execute(task); + return task; + } + + /** + * Executes {@code callable} on the specified {@code executor}, returning a {@code Future}. + * + * @throws RejectedExecutionException if the task cannot be scheduled for execution + * @since 23.0 + */ + public static ListenableFuture submitAsync( + AsyncCallable callable, Executor executor) { + TrustedListenableFutureTask task = TrustedListenableFutureTask.create(callable); + executor.execute(task); + return task; + } + + /** + * Schedules {@code callable} on the specified {@code executor}, returning a {@code Future}. + * + * @throws RejectedExecutionException if the task cannot be scheduled for execution + * @since 28.0 + */ + @GwtIncompatible // java.util.concurrent.ScheduledExecutorService + // TODO(cpovirk): Return ListenableScheduledFuture? + public static ListenableFuture scheduleAsync( + AsyncCallable callable, Duration delay, ScheduledExecutorService executorService) { + return scheduleAsync(callable, toNanosSaturated(delay), TimeUnit.NANOSECONDS, executorService); + } + + /** + * Schedules {@code callable} on the specified {@code executor}, returning a {@code Future}. + * + * @throws RejectedExecutionException if the task cannot be scheduled for execution + * @since 23.0 + */ + @GwtIncompatible // java.util.concurrent.ScheduledExecutorService + @SuppressWarnings("GoodTime") // should accept a java.time.Duration + // TODO(cpovirk): Return ListenableScheduledFuture? + public static ListenableFuture scheduleAsync( + AsyncCallable callable, + long delay, + TimeUnit timeUnit, + ScheduledExecutorService executorService) { + TrustedListenableFutureTask task = TrustedListenableFutureTask.create(callable); + final Future scheduled = executorService.schedule(task, delay, timeUnit); + task.addListener( + new Runnable() { + @Override + public void run() { + // Don't want to interrupt twice + scheduled.cancel(false); + } + }, + directExecutor()); + return task; + } + + /** + * Returns a {@code Future} whose result is taken from the given primary {@code input} or, if the + * primary input fails with the given {@code exceptionType}, from the result provided by the + * {@code fallback}. {@link Function#apply} is not invoked until the primary input has failed, so + * if the primary input succeeds, it is never invoked. If, during the invocation of {@code + * fallback}, an exception is thrown, this exception is used as the result of the output {@code + * Future}. + * + *

Usage example: + * + *

{@code
+   * ListenableFuture fetchCounterFuture = ...;
+   *
+   * // Falling back to a zero counter in case an exception happens when
+   * // processing the RPC to fetch counters.
+   * ListenableFuture faultTolerantFuture = Futures.catching(
+   *     fetchCounterFuture, FetchException.class, x -> 0, directExecutor());
+   * }
+ * + *

When selecting an executor, note that {@code directExecutor} is dangerous in some cases. See + * the warnings the {@link MoreExecutors#directExecutor} documentation. + * + * @param input the primary input {@code Future} + * @param exceptionType the exception type that triggers use of {@code fallback}. The exception + * type is matched against the input's exception. "The input's exception" means the cause of + * the {@link ExecutionException} thrown by {@code input.get()} or, if {@code get()} throws a + * different kind of exception, that exception itself. To avoid hiding bugs and other + * unrecoverable errors, callers should prefer more specific types, avoiding {@code + * Throwable.class} in particular. + * @param fallback the {@link Function} to be called if {@code input} fails with the expected + * exception type. The function's argument is the input's exception. "The input's exception" + * means the cause of the {@link ExecutionException} thrown by {@code input.get()} or, if + * {@code get()} throws a different kind of exception, that exception itself. + * @param executor the executor that runs {@code fallback} if {@code input} fails + * @since 19.0 + */ + @Beta + @Partially.GwtIncompatible("AVAILABLE but requires exceptionType to be Throwable.class") + public static ListenableFuture catching( + ListenableFuture input, + Class exceptionType, + Function fallback, + Executor executor) { + return AbstractCatchingFuture.create(input, exceptionType, fallback, executor); + } + + /** + * Returns a {@code Future} whose result is taken from the given primary {@code input} or, if the + * primary input fails with the given {@code exceptionType}, from the result provided by the + * {@code fallback}. {@link AsyncFunction#apply} is not invoked until the primary input has + * failed, so if the primary input succeeds, it is never invoked. If, during the invocation of + * {@code fallback}, an exception is thrown, this exception is used as the result of the output + * {@code Future}. + * + *

Usage examples: + * + *

{@code
+   * ListenableFuture fetchCounterFuture = ...;
+   *
+   * // Falling back to a zero counter in case an exception happens when
+   * // processing the RPC to fetch counters.
+   * ListenableFuture faultTolerantFuture = Futures.catchingAsync(
+   *     fetchCounterFuture, FetchException.class, x -> immediateFuture(0), directExecutor());
+   * }
+ * + *

The fallback can also choose to propagate the original exception when desired: + * + *

{@code
+   * ListenableFuture fetchCounterFuture = ...;
+   *
+   * // Falling back to a zero counter only in case the exception was a
+   * // TimeoutException.
+   * ListenableFuture faultTolerantFuture = Futures.catchingAsync(
+   *     fetchCounterFuture,
+   *     FetchException.class,
+   *     e -> {
+   *       if (omitDataOnFetchFailure) {
+   *         return immediateFuture(0);
+   *       }
+   *       throw e;
+   *     },
+   *     directExecutor());
+   * }
+ * + *

When selecting an executor, note that {@code directExecutor} is dangerous in some cases. See + * the warnings the {@link MoreExecutors#directExecutor} documentation. + * + * @param input the primary input {@code Future} + * @param exceptionType the exception type that triggers use of {@code fallback}. The exception + * type is matched against the input's exception. "The input's exception" means the cause of + * the {@link ExecutionException} thrown by {@code input.get()} or, if {@code get()} throws a + * different kind of exception, that exception itself. To avoid hiding bugs and other + * unrecoverable errors, callers should prefer more specific types, avoiding {@code + * Throwable.class} in particular. + * @param fallback the {@link AsyncFunction} to be called if {@code input} fails with the expected + * exception type. The function's argument is the input's exception. "The input's exception" + * means the cause of the {@link ExecutionException} thrown by {@code input.get()} or, if + * {@code get()} throws a different kind of exception, that exception itself. + * @param executor the executor that runs {@code fallback} if {@code input} fails + * @since 19.0 (similar functionality in 14.0 as {@code withFallback}) + */ + @Beta + @Partially.GwtIncompatible("AVAILABLE but requires exceptionType to be Throwable.class") + public static ListenableFuture catchingAsync( + ListenableFuture input, + Class exceptionType, + AsyncFunction fallback, + Executor executor) { + return AbstractCatchingFuture.create(input, exceptionType, fallback, executor); + } + + /** + * Returns a future that delegates to another but will finish early (via a {@link + * TimeoutException} wrapped in an {@link ExecutionException}) if the specified duration expires. + * + *

The delegate future is interrupted and cancelled if it times out. + * + * @param delegate The future to delegate to. + * @param time when to timeout the future + * @param scheduledExecutor The executor service to enforce the timeout. + * @since 28.0 + */ + @Beta + @GwtIncompatible // java.util.concurrent.ScheduledExecutorService + public static ListenableFuture withTimeout( + ListenableFuture delegate, Duration time, ScheduledExecutorService scheduledExecutor) { + return withTimeout(delegate, toNanosSaturated(time), TimeUnit.NANOSECONDS, scheduledExecutor); + } + + /** + * Returns a future that delegates to another but will finish early (via a {@link + * TimeoutException} wrapped in an {@link ExecutionException}) if the specified duration expires. + * + *

The delegate future is interrupted and cancelled if it times out. + * + * @param delegate The future to delegate to. + * @param time when to timeout the future + * @param unit the time unit of the time parameter + * @param scheduledExecutor The executor service to enforce the timeout. + * @since 19.0 + */ + @Beta + @GwtIncompatible // java.util.concurrent.ScheduledExecutorService + @SuppressWarnings("GoodTime") // should accept a java.time.Duration + public static ListenableFuture withTimeout( + ListenableFuture delegate, + long time, + TimeUnit unit, + ScheduledExecutorService scheduledExecutor) { + if (delegate.isDone()) { + return delegate; + } + return TimeoutFuture.create(delegate, time, unit, scheduledExecutor); + } + + /** + * Returns a new {@code Future} whose result is asynchronously derived from the result of the + * given {@code Future}. If the given {@code Future} fails, the returned {@code Future} fails with + * the same exception (and the function is not invoked). + * + *

More precisely, the returned {@code Future} takes its result from a {@code Future} produced + * by applying the given {@code AsyncFunction} to the result of the original {@code Future}. + * Example usage: + * + *

{@code
+   * ListenableFuture rowKeyFuture = indexService.lookUp(query);
+   * ListenableFuture queryFuture =
+   *     transformAsync(rowKeyFuture, dataService::readFuture, executor);
+   * }
+ * + *

When selecting an executor, note that {@code directExecutor} is dangerous in some cases. See + * the warnings the {@link MoreExecutors#directExecutor} documentation. + * + *

The returned {@code Future} attempts to keep its cancellation state in sync with that of the + * input future and that of the future returned by the chain function. That is, if the returned + * {@code Future} is cancelled, it will attempt to cancel the other two, and if either of the + * other two is cancelled, the returned {@code Future} will receive a callback in which it will + * attempt to cancel itself. + * + * @param input The future to transform + * @param function A function to transform the result of the input future to the result of the + * output future + * @param executor Executor to run the function in. + * @return A future that holds result of the function (if the input succeeded) or the original + * input's failure (if not) + * @since 19.0 (in 11.0 as {@code transform}) + */ + @Beta + public static + ListenableFuture transformAsync( + ListenableFuture input, + AsyncFunction function, + Executor executor) { + return AbstractTransformFuture.create(input, function, executor); + } + + /** + * Returns a new {@code Future} whose result is derived from the result of the given {@code + * Future}. If {@code input} fails, the returned {@code Future} fails with the same exception (and + * the function is not invoked). Example usage: + * + *

{@code
+   * ListenableFuture queryFuture = ...;
+   * ListenableFuture> rowsFuture =
+   *     transform(queryFuture, QueryResult::getRows, executor);
+   * }
+ * + *

When selecting an executor, note that {@code directExecutor} is dangerous in some cases. See + * the warnings the {@link MoreExecutors#directExecutor} documentation. + * + *

The returned {@code Future} attempts to keep its cancellation state in sync with that of the + * input future. That is, if the returned {@code Future} is cancelled, it will attempt to cancel + * the input, and if the input is cancelled, the returned {@code Future} will receive a callback + * in which it will attempt to cancel itself. + * + *

An example use of this method is to convert a serializable object returned from an RPC into + * a POJO. + * + * @param input The future to transform + * @param function A Function to transform the results of the provided future to the results of + * the returned future. + * @param executor Executor to run the function in. + * @return A future that holds result of the transformation. + * @since 9.0 (in 2.0 as {@code compose}) + */ + @Beta + public static + ListenableFuture transform( + ListenableFuture input, Function function, Executor executor) { + return AbstractTransformFuture.create(input, function, executor); + } + + /** + * Like {@link #transform(ListenableFuture, Function, Executor)} except that the transformation + * {@code function} is invoked on each call to {@link Future#get() get()} on the returned future. + * + *

The returned {@code Future} reflects the input's cancellation state directly, and any + * attempt to cancel the returned Future is likewise passed through to the input Future. + * + *

Note that calls to {@linkplain Future#get(long, TimeUnit) timed get} only apply the timeout + * to the execution of the underlying {@code Future}, not to the execution of the + * transformation function. + * + *

The primary audience of this method is callers of {@code transform} who don't have a {@code + * ListenableFuture} available and do not mind repeated, lazy function evaluation. + * + * @param input The future to transform + * @param function A Function to transform the results of the provided future to the results of + * the returned future. + * @return A future that returns the result of the transformation. + * @since 10.0 + */ + @Beta + @GwtIncompatible // TODO + public static Future lazyTransform( + final Future input, final Function function) { + checkNotNull(input); + checkNotNull(function); + return new Future() { + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + return input.cancel(mayInterruptIfRunning); + } + + @Override + public boolean isCancelled() { + return input.isCancelled(); + } + + @Override + public boolean isDone() { + return input.isDone(); + } + + @Override + public O get() throws InterruptedException, ExecutionException { + return applyTransformation(input.get()); + } + + @Override + public O get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + return applyTransformation(input.get(timeout, unit)); + } + + private O applyTransformation(I input) throws ExecutionException { + try { + return function.apply(input); + } catch (Throwable t) { + throw new ExecutionException(t); + } + } + }; + } + + /** + * Creates a new {@code ListenableFuture} whose value is a list containing the values of all its + * input futures, if all succeed. + * + *

The list of results is in the same order as the input list. + * + *

This differs from {@link #successfulAsList(ListenableFuture[])} in that it will return a + * failed future if any of the items fails. + * + *

Canceling this future will attempt to cancel all the component futures, and if any of the + * provided futures fails or is canceled, this one is, too. + * + * @param futures futures to combine + * @return a future that provides a list of the results of the component futures + * @since 10.0 + */ + @Beta + @SafeVarargs + public static ListenableFuture> allAsList( + ListenableFuture... futures) { + ListenableFuture> nullable = + new ListFuture(ImmutableList.copyOf(futures), true); + // allAsList ensures that it fills the output list with V instances. + @SuppressWarnings("nullness") + ListenableFuture> nonNull = nullable; + return nonNull; + } + + /** + * Creates a new {@code ListenableFuture} whose value is a list containing the values of all its + * input futures, if all succeed. + * + *

The list of results is in the same order as the input list. + * + *

This differs from {@link #successfulAsList(Iterable)} in that it will return a failed future + * if any of the items fails. + * + *

Canceling this future will attempt to cancel all the component futures, and if any of the + * provided futures fails or is canceled, this one is, too. + * + * @param futures futures to combine + * @return a future that provides a list of the results of the component futures + * @since 10.0 + */ + @Beta + public static ListenableFuture> allAsList( + Iterable> futures) { + ListenableFuture> nullable = + new ListFuture(ImmutableList.copyOf(futures), true); + // allAsList ensures that it fills the output list with V instances. + @SuppressWarnings("nullness") + ListenableFuture> nonNull = nullable; + return nonNull; + } + + /** + * Creates a {@link FutureCombiner} that processes the completed futures whether or not they're + * successful. + * + *

Any failures from the input futures will not be propagated to the returned future. + * + * @since 20.0 + */ + @Beta + @SafeVarargs + public static FutureCombiner whenAllComplete( + ListenableFuture... futures) { + return new FutureCombiner(false, ImmutableList.copyOf(futures)); + } + + /** + * Creates a {@link FutureCombiner} that processes the completed futures whether or not they're + * successful. + * + *

Any failures from the input futures will not be propagated to the returned future. + * + * @since 20.0 + */ + @Beta + public static FutureCombiner whenAllComplete( + Iterable> futures) { + return new FutureCombiner(false, ImmutableList.copyOf(futures)); + } + + /** + * Creates a {@link FutureCombiner} requiring that all passed in futures are successful. + * + *

If any input fails, the returned future fails immediately. + * + * @since 20.0 + */ + @Beta + @SafeVarargs + public static FutureCombiner whenAllSucceed( + ListenableFuture... futures) { + return new FutureCombiner(true, ImmutableList.copyOf(futures)); + } + + /** + * Creates a {@link FutureCombiner} requiring that all passed in futures are successful. + * + *

If any input fails, the returned future fails immediately. + * + * @since 20.0 + */ + @Beta + public static FutureCombiner whenAllSucceed( + Iterable> futures) { + return new FutureCombiner(true, ImmutableList.copyOf(futures)); + } + + /** + * A helper to create a new {@code ListenableFuture} whose result is generated from a combination + * of input futures. + * + *

See {@link #whenAllComplete} and {@link #whenAllSucceed} for how to instantiate this class. + * + *

Example: + * + *

{@code
+   * final ListenableFuture loginDateFuture =
+   *     loginService.findLastLoginDate(username);
+   * final ListenableFuture> recentCommandsFuture =
+   *     recentCommandsService.findRecentCommands(username);
+   * ListenableFuture usageFuture =
+   *     Futures.whenAllSucceed(loginDateFuture, recentCommandsFuture)
+   *         .call(
+   *             () ->
+   *                 new UsageHistory(
+   *                     username,
+   *                     Futures.getDone(loginDateFuture),
+   *                     Futures.getDone(recentCommandsFuture)),
+   *             executor);
+   * }
+ * + * @since 20.0 + */ + @Beta + @CanIgnoreReturnValue // TODO(cpovirk): Consider removing, especially if we provide run(Runnable) + @GwtCompatible + public static final class FutureCombiner { + private final boolean allMustSucceed; + private final ImmutableList> futures; + + private FutureCombiner( + boolean allMustSucceed, ImmutableList> futures) { + this.allMustSucceed = allMustSucceed; + this.futures = futures; + } + + /** + * Creates the {@link ListenableFuture} which will return the result of calling {@link + * AsyncCallable#call} in {@code combiner} when all futures complete, using the specified {@code + * executor}. + * + *

If the combiner throws a {@code CancellationException}, the returned future will be + * cancelled. + * + *

If the combiner throws an {@code ExecutionException}, the cause of the thrown {@code + * ExecutionException} will be extracted and returned as the cause of the new {@code + * ExecutionException} that gets thrown by the returned combined future. + * + *

Canceling this future will attempt to cancel all the component futures. + */ + public ListenableFuture callAsync( + AsyncCallable combiner, Executor executor) { + return new CombinedFuture(futures, allMustSucceed, executor, combiner); + } + + /** + * Creates the {@link ListenableFuture} which will return the result of calling {@link + * Callable#call} in {@code combiner} when all futures complete, using the specified {@code + * executor}. + * + *

If the combiner throws a {@code CancellationException}, the returned future will be + * cancelled. + * + *

If the combiner throws an {@code ExecutionException}, the cause of the thrown {@code + * ExecutionException} will be extracted and returned as the cause of the new {@code + * ExecutionException} that gets thrown by the returned combined future. + * + *

Canceling this future will attempt to cancel all the component futures. + */ + @CanIgnoreReturnValue // TODO(cpovirk): Remove this + public ListenableFuture call( + Callable combiner, Executor executor) { + return new CombinedFuture(futures, allMustSucceed, executor, combiner); + } + + /** + * Creates the {@link ListenableFuture} which will return the result of running {@code combiner} + * when all Futures complete. {@code combiner} will run using {@code executor}. + * + *

If the combiner throws a {@code CancellationException}, the returned future will be + * cancelled. + * + *

Canceling this Future will attempt to cancel all the component futures. + * + * @since 23.6 + */ + public ListenableFuture run(final Runnable combiner, Executor executor) { + return call( + new Callable<@Nullable Void>() { + @Override + @CheckForNull + public Void call() throws Exception { + combiner.run(); + return null; + } + }, + executor); + } + } + + /** + * Returns a {@code ListenableFuture} whose result is set from the supplied future when it + * completes. Cancelling the supplied future will also cancel the returned future, but cancelling + * the returned future will have no effect on the supplied future. + * + * @since 15.0 + */ + public static ListenableFuture nonCancellationPropagating( + ListenableFuture future) { + if (future.isDone()) { + return future; + } + NonCancellationPropagatingFuture output = new NonCancellationPropagatingFuture<>(future); + future.addListener(output, directExecutor()); + return output; + } + + /** A wrapped future that does not propagate cancellation to its delegate. */ + private static final class NonCancellationPropagatingFuture + extends AbstractFuture.TrustedFuture implements Runnable { + @CheckForNull private ListenableFuture delegate; + + NonCancellationPropagatingFuture(final ListenableFuture delegate) { + this.delegate = delegate; + } + + @Override + public void run() { + // This prevents cancellation from propagating because we don't call setFuture(delegate) until + // delegate is already done, so calling cancel() on this future won't affect it. + ListenableFuture localDelegate = delegate; + if (localDelegate != null) { + setFuture(localDelegate); + } + } + + @Override + @CheckForNull + protected String pendingToString() { + ListenableFuture localDelegate = delegate; + if (localDelegate != null) { + return "delegate=[" + localDelegate + "]"; + } + return null; + } + + @Override + protected void afterDone() { + delegate = null; + } + } + + /** + * Creates a new {@code ListenableFuture} whose value is a list containing the values of all its + * successful input futures. The list of results is in the same order as the input list, and if + * any of the provided futures fails or is canceled, its corresponding position will contain + * {@code null} (which is indistinguishable from the future having a successful value of {@code + * null}). + * + *

The list of results is in the same order as the input list. + * + *

This differs from {@link #allAsList(ListenableFuture[])} in that it's tolerant of failed + * futures for any of the items, representing them as {@code null} in the result list. + * + *

Canceling this future will attempt to cancel all the component futures. + * + * @param futures futures to combine + * @return a future that provides a list of the results of the component futures + * @since 10.0 + */ + @Beta + @SafeVarargs + public static ListenableFuture> successfulAsList( + ListenableFuture... futures) { + /* + * Another way to express this signature would be to bound by @NonNull and accept + * LF. That might be better: There's currently no difference between the + * outputs users get when calling this with and calling it with <@Nullable Foo>. The only + * difference is that calling it with won't work when an input Future has a @Nullable + * type. So why even make that error possible by giving callers the choice? + * + * On the other hand, the current signature is consistent with the similar allAsList method. And + * eventually this method may go away entirely in favor of an API like + * whenAllComplete().collectSuccesses(). That API would have a signature more like the current + * one. + */ + return new ListFuture(ImmutableList.copyOf(futures), false); + } + + /** + * Creates a new {@code ListenableFuture} whose value is a list containing the values of all its + * successful input futures. The list of results is in the same order as the input list, and if + * any of the provided futures fails or is canceled, its corresponding position will contain + * {@code null} (which is indistinguishable from the future having a successful value of {@code + * null}). + * + *

The list of results is in the same order as the input list. + * + *

This differs from {@link #allAsList(Iterable)} in that it's tolerant of failed futures for + * any of the items, representing them as {@code null} in the result list. + * + *

Canceling this future will attempt to cancel all the component futures. + * + * @param futures futures to combine + * @return a future that provides a list of the results of the component futures + * @since 10.0 + */ + @Beta + public static ListenableFuture> successfulAsList( + Iterable> futures) { + return new ListFuture(ImmutableList.copyOf(futures), false); + } + + /** + * Returns a list of delegate futures that correspond to the futures received in the order that + * they complete. Delegate futures return the same value or throw the same exception as the + * corresponding input future returns/throws. + * + *

"In the order that they complete" means, for practical purposes, about what you would + * expect, but there are some subtleties. First, we do guarantee that, if the output future at + * index n is done, the output future at index n-1 is also done. (But as usual with futures, some + * listeners for future n may complete before some for future n-1.) However, it is possible, if + * one input completes with result X and another later with result Y, for Y to come before X in + * the output future list. (Such races are impossible to solve without global synchronization of + * all future completions. And they should have little practical impact.) + * + *

Cancelling a delegate future propagates to input futures once all the delegates complete, + * either from cancellation or because an input future has completed. If N futures are passed in, + * and M delegates are cancelled, the remaining M input futures will be cancelled once N - M of + * the input futures complete. If all the delegates are cancelled, all the input futures will be + * too. + * + * @since 17.0 + */ + public static ImmutableList> inCompletionOrder( + Iterable> futures) { + ListenableFuture[] copy = gwtCompatibleToArray(futures); + final InCompletionOrderState state = new InCompletionOrderState<>(copy); + ImmutableList.Builder> delegatesBuilder = + ImmutableList.builderWithExpectedSize(copy.length); + for (int i = 0; i < copy.length; i++) { + delegatesBuilder.add(new InCompletionOrderFuture(state)); + } + + final ImmutableList> delegates = delegatesBuilder.build(); + for (int i = 0; i < copy.length; i++) { + final int localI = i; + copy[i].addListener( + new Runnable() { + @Override + public void run() { + state.recordInputCompletion(delegates, localI); + } + }, + directExecutor()); + } + + @SuppressWarnings("unchecked") + ImmutableList> delegatesCast = (ImmutableList) delegates; + return delegatesCast; + } + + /** Can't use Iterables.toArray because it's not gwt compatible */ + @SuppressWarnings("unchecked") + private static ListenableFuture[] gwtCompatibleToArray( + Iterable> futures) { + final Collection> collection; + if (futures instanceof Collection) { + collection = (Collection>) futures; + } else { + collection = ImmutableList.copyOf(futures); + } + return (ListenableFuture[]) collection.toArray(new ListenableFuture[0]); + } + + // This can't be a TrustedFuture, because TrustedFuture has clever optimizations that + // mean cancel won't be called if this Future is passed into setFuture, and then + // cancelled. + private static final class InCompletionOrderFuture + extends AbstractFuture { + @CheckForNull private InCompletionOrderState state; + + private InCompletionOrderFuture(InCompletionOrderState state) { + this.state = state; + } + + @Override + public boolean cancel(boolean interruptIfRunning) { + InCompletionOrderState localState = state; + if (super.cancel(interruptIfRunning)) { + /* + * requireNonNull is generally safe: If cancel succeeded, then this Future was still + * pending, so its `state` field hasn't been nulled out yet. + * + * OK, it's technically possible for this to fail in the presence of unsafe publishing, as + * discussed in the comments in TimeoutFuture. TODO(cpovirk): Maybe check for null before + * calling recordOutputCancellation? + */ + requireNonNull(localState).recordOutputCancellation(interruptIfRunning); + return true; + } + return false; + } + + @Override + protected void afterDone() { + state = null; + } + + @Override + @CheckForNull + protected String pendingToString() { + InCompletionOrderState localState = state; + if (localState != null) { + // Don't print the actual array! We don't want inCompletionOrder(list).toString() to have + // quadratic output. + return "inputCount=[" + + localState.inputFutures.length + + "], remaining=[" + + localState.incompleteOutputCount.get() + + "]"; + } + return null; + } + } + + private static final class InCompletionOrderState { + // A happens-before edge between the writes of these fields and their reads exists, because + // in order to read these fields, the corresponding write to incompleteOutputCount must have + // been read. + private boolean wasCancelled = false; + private boolean shouldInterrupt = true; + private final AtomicInteger incompleteOutputCount; + // We set the elements of the array to null as they complete. + private final @Nullable ListenableFuture[] inputFutures; + private volatile int delegateIndex = 0; + + private InCompletionOrderState(ListenableFuture[] inputFutures) { + this.inputFutures = inputFutures; + incompleteOutputCount = new AtomicInteger(inputFutures.length); + } + + private void recordOutputCancellation(boolean interruptIfRunning) { + wasCancelled = true; + // If all the futures were cancelled with interruption, cancel the input futures + // with interruption; otherwise cancel without + if (!interruptIfRunning) { + shouldInterrupt = false; + } + recordCompletion(); + } + + private void recordInputCompletion( + ImmutableList> delegates, int inputFutureIndex) { + /* + * requireNonNull is safe because we accepted an Iterable of non-null Future instances, and we + * don't overwrite an element in the array until after reading it. + */ + ListenableFuture inputFuture = requireNonNull(inputFutures[inputFutureIndex]); + // Null out our reference to this future, so it can be GCed + inputFutures[inputFutureIndex] = null; + for (int i = delegateIndex; i < delegates.size(); i++) { + if (delegates.get(i).setFuture(inputFuture)) { + recordCompletion(); + // this is technically unnecessary, but should speed up later accesses + delegateIndex = i + 1; + return; + } + } + // If all the delegates were complete, no reason for the next listener to have to + // go through the whole list. Avoids O(n^2) behavior when the entire output list is + // cancelled. + delegateIndex = delegates.size(); + } + + private void recordCompletion() { + if (incompleteOutputCount.decrementAndGet() == 0 && wasCancelled) { + for (ListenableFuture toCancel : inputFutures) { + if (toCancel != null) { + toCancel.cancel(shouldInterrupt); + } + } + } + } + } + + /** + * Registers separate success and failure callbacks to be run when the {@code Future}'s + * computation is {@linkplain java.util.concurrent.Future#isDone() complete} or, if the + * computation is already complete, immediately. + * + *

The callback is run on {@code executor}. There is no guaranteed ordering of execution of + * callbacks, but any callback added through this method is guaranteed to be called once the + * computation is complete. + * + *

Exceptions thrown by a {@code callback} will be propagated up to the executor. Any exception + * thrown during {@code Executor.execute} (e.g., a {@code RejectedExecutionException} or an + * exception thrown by {@linkplain MoreExecutors#directExecutor direct execution}) will be caught + * and logged. + * + *

Example: + * + *

{@code
+   * ListenableFuture future = ...;
+   * Executor e = ...
+   * addCallback(future,
+   *     new FutureCallback() {
+   *       public void onSuccess(QueryResult result) {
+   *         storeInCache(result);
+   *       }
+   *       public void onFailure(Throwable t) {
+   *         reportError(t);
+   *       }
+   *     }, e);
+   * }
+ * + *

When selecting an executor, note that {@code directExecutor} is dangerous in some cases. See + * the warnings the {@link MoreExecutors#directExecutor} documentation. + * + *

For a more general interface to attach a completion listener to a {@code Future}, see {@link + * ListenableFuture#addListener addListener}. + * + * @param future The future attach the callback to. + * @param callback The callback to invoke when {@code future} is completed. + * @param executor The executor to run {@code callback} when the future completes. + * @since 10.0 + */ + public static void addCallback( + final ListenableFuture future, + final FutureCallback callback, + Executor executor) { + Preconditions.checkNotNull(callback); + future.addListener(new CallbackListener(future, callback), executor); + } + + /** See {@link #addCallback(ListenableFuture, FutureCallback, Executor)} for behavioral notes. */ + private static final class CallbackListener implements Runnable { + final Future future; + final FutureCallback callback; + + CallbackListener(Future future, FutureCallback callback) { + this.future = future; + this.callback = callback; + } + + @Override + public void run() { + if (future instanceof InternalFutureFailureAccess) { + Throwable failure = + InternalFutures.tryInternalFastPathGetFailure((InternalFutureFailureAccess) future); + if (failure != null) { + callback.onFailure(failure); + return; + } + } + final V value; + try { + value = getDone(future); + } catch (ExecutionException e) { + callback.onFailure(e.getCause()); + return; + } catch (RuntimeException | Error e) { + callback.onFailure(e); + return; + } + callback.onSuccess(value); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).addValue(callback).toString(); + } + } + + /** + * Returns the result of the input {@code Future}, which must have already completed. + * + *

The benefits of this method are twofold. First, the name "getDone" suggests to readers that + * the {@code Future} is already done. Second, if buggy code calls {@code getDone} on a {@code + * Future} that is still pending, the program will throw instead of block. This can be important + * for APIs like {@link #whenAllComplete whenAllComplete(...)}{@code .}{@link + * FutureCombiner#call(Callable, Executor) call(...)}, where it is easy to use a new input from + * the {@code call} implementation but forget to add it to the arguments of {@code + * whenAllComplete}. + * + *

If you are looking for a method to determine whether a given {@code Future} is done, use the + * instance method {@link Future#isDone()}. + * + * @throws ExecutionException if the {@code Future} failed with an exception + * @throws CancellationException if the {@code Future} was cancelled + * @throws IllegalStateException if the {@code Future} is not done + * @since 20.0 + */ + @CanIgnoreReturnValue + // TODO(cpovirk): Consider calling getDone() in our own code. + @ParametricNullness + public static V getDone(Future future) throws ExecutionException { + /* + * We throw IllegalStateException, since the call could succeed later. Perhaps we "should" throw + * IllegalArgumentException, since the call could succeed with a different argument. Those + * exceptions' docs suggest that either is acceptable. Google's Java Practices page recommends + * IllegalArgumentException here, in part to keep its recommendation simple: Static methods + * should throw IllegalStateException only when they use static state. + * + * Why do we deviate here? The answer: We want for fluentFuture.getDone() to throw the same + * exception as Futures.getDone(fluentFuture). + */ + checkState(future.isDone(), "Future was expected to be done: %s", future); + return getUninterruptibly(future); + } + + /** + * Returns the result of {@link Future#get()}, converting most exceptions to a new instance of the + * given checked exception type. This reduces boilerplate for a common use of {@code Future} in + * which it is unnecessary to programmatically distinguish between exception types or to extract + * other information from the exception instance. + * + *

Exceptions from {@code Future.get} are treated as follows: + * + *

    + *
  • Any {@link ExecutionException} has its cause wrapped in an {@code X} if the cause + * is a checked exception, an {@link UncheckedExecutionException} if the cause is a {@code + * RuntimeException}, or an {@link ExecutionError} if the cause is an {@code Error}. + *
  • Any {@link InterruptedException} is wrapped in an {@code X} (after restoring the + * interrupt). + *
  • Any {@link CancellationException} is propagated untouched, as is any other {@link + * RuntimeException} (though {@code get} implementations are discouraged from throwing such + * exceptions). + *
+ * + *

The overall principle is to continue to treat every checked exception as a checked + * exception, every unchecked exception as an unchecked exception, and every error as an error. In + * addition, the cause of any {@code ExecutionException} is wrapped in order to ensure that the + * new stack trace matches that of the current thread. + * + *

Instances of {@code exceptionClass} are created by choosing an arbitrary public constructor + * that accepts zero or more arguments, all of type {@code String} or {@code Throwable} + * (preferring constructors with at least one {@code String}) and calling the constructor via + * reflection. If the exception did not already have a cause, one is set by calling {@link + * Throwable#initCause(Throwable)} on it. If no such constructor exists, an {@code + * IllegalArgumentException} is thrown. + * + * @throws X if {@code get} throws any checked exception except for an {@code ExecutionException} + * whose cause is not itself a checked exception + * @throws UncheckedExecutionException if {@code get} throws an {@code ExecutionException} with a + * {@code RuntimeException} as its cause + * @throws ExecutionError if {@code get} throws an {@code ExecutionException} with an {@code + * Error} as its cause + * @throws CancellationException if {@code get} throws a {@code CancellationException} + * @throws IllegalArgumentException if {@code exceptionClass} extends {@code RuntimeException} or + * does not have a suitable constructor + * @since 19.0 (in 10.0 as {@code get}) + */ + @Beta + @CanIgnoreReturnValue + @GwtIncompatible // reflection + @ParametricNullness + public static V getChecked( + Future future, Class exceptionClass) throws X { + return FuturesGetChecked.getChecked(future, exceptionClass); + } + + /** + * Returns the result of {@link Future#get(long, TimeUnit)}, converting most exceptions to a new + * instance of the given checked exception type. This reduces boilerplate for a common use of + * {@code Future} in which it is unnecessary to programmatically distinguish between exception + * types or to extract other information from the exception instance. + * + *

Exceptions from {@code Future.get} are treated as follows: + * + *

    + *
  • Any {@link ExecutionException} has its cause wrapped in an {@code X} if the cause + * is a checked exception, an {@link UncheckedExecutionException} if the cause is a {@code + * RuntimeException}, or an {@link ExecutionError} if the cause is an {@code Error}. + *
  • Any {@link InterruptedException} is wrapped in an {@code X} (after restoring the + * interrupt). + *
  • Any {@link TimeoutException} is wrapped in an {@code X}. + *
  • Any {@link CancellationException} is propagated untouched, as is any other {@link + * RuntimeException} (though {@code get} implementations are discouraged from throwing such + * exceptions). + *
+ * + *

The overall principle is to continue to treat every checked exception as a checked + * exception, every unchecked exception as an unchecked exception, and every error as an error. In + * addition, the cause of any {@code ExecutionException} is wrapped in order to ensure that the + * new stack trace matches that of the current thread. + * + *

Instances of {@code exceptionClass} are created by choosing an arbitrary public constructor + * that accepts zero or more arguments, all of type {@code String} or {@code Throwable} + * (preferring constructors with at least one {@code String}) and calling the constructor via + * reflection. If the exception did not already have a cause, one is set by calling {@link + * Throwable#initCause(Throwable)} on it. If no such constructor exists, an {@code + * IllegalArgumentException} is thrown. + * + * @throws X if {@code get} throws any checked exception except for an {@code ExecutionException} + * whose cause is not itself a checked exception + * @throws UncheckedExecutionException if {@code get} throws an {@code ExecutionException} with a + * {@code RuntimeException} as its cause + * @throws ExecutionError if {@code get} throws an {@code ExecutionException} with an {@code + * Error} as its cause + * @throws CancellationException if {@code get} throws a {@code CancellationException} + * @throws IllegalArgumentException if {@code exceptionClass} extends {@code RuntimeException} or + * does not have a suitable constructor + * @since 28.0 + */ + @Beta + @CanIgnoreReturnValue + @GwtIncompatible // reflection + @ParametricNullness + public static V getChecked( + Future future, Class exceptionClass, Duration timeout) throws X { + return getChecked(future, exceptionClass, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); + } + + /** + * Returns the result of {@link Future#get(long, TimeUnit)}, converting most exceptions to a new + * instance of the given checked exception type. This reduces boilerplate for a common use of + * {@code Future} in which it is unnecessary to programmatically distinguish between exception + * types or to extract other information from the exception instance. + * + *

Exceptions from {@code Future.get} are treated as follows: + * + *

    + *
  • Any {@link ExecutionException} has its cause wrapped in an {@code X} if the cause + * is a checked exception, an {@link UncheckedExecutionException} if the cause is a {@code + * RuntimeException}, or an {@link ExecutionError} if the cause is an {@code Error}. + *
  • Any {@link InterruptedException} is wrapped in an {@code X} (after restoring the + * interrupt). + *
  • Any {@link TimeoutException} is wrapped in an {@code X}. + *
  • Any {@link CancellationException} is propagated untouched, as is any other {@link + * RuntimeException} (though {@code get} implementations are discouraged from throwing such + * exceptions). + *
+ * + *

The overall principle is to continue to treat every checked exception as a checked + * exception, every unchecked exception as an unchecked exception, and every error as an error. In + * addition, the cause of any {@code ExecutionException} is wrapped in order to ensure that the + * new stack trace matches that of the current thread. + * + *

Instances of {@code exceptionClass} are created by choosing an arbitrary public constructor + * that accepts zero or more arguments, all of type {@code String} or {@code Throwable} + * (preferring constructors with at least one {@code String}) and calling the constructor via + * reflection. If the exception did not already have a cause, one is set by calling {@link + * Throwable#initCause(Throwable)} on it. If no such constructor exists, an {@code + * IllegalArgumentException} is thrown. + * + * @throws X if {@code get} throws any checked exception except for an {@code ExecutionException} + * whose cause is not itself a checked exception + * @throws UncheckedExecutionException if {@code get} throws an {@code ExecutionException} with a + * {@code RuntimeException} as its cause + * @throws ExecutionError if {@code get} throws an {@code ExecutionException} with an {@code + * Error} as its cause + * @throws CancellationException if {@code get} throws a {@code CancellationException} + * @throws IllegalArgumentException if {@code exceptionClass} extends {@code RuntimeException} or + * does not have a suitable constructor + * @since 19.0 (in 10.0 as {@code get} and with different parameter order) + */ + @Beta + @CanIgnoreReturnValue + @GwtIncompatible // reflection + @SuppressWarnings("GoodTime") // should accept a java.time.Duration + @ParametricNullness + public static V getChecked( + Future future, Class exceptionClass, long timeout, TimeUnit unit) throws X { + return FuturesGetChecked.getChecked(future, exceptionClass, timeout, unit); + } + + /** + * Returns the result of calling {@link Future#get()} uninterruptibly on a task known not to throw + * a checked exception. This makes {@code Future} more suitable for lightweight, fast-running + * tasks that, barring bugs in the code, will not fail. This gives it exception-handling behavior + * similar to that of {@code ForkJoinTask.join}. + * + *

Exceptions from {@code Future.get} are treated as follows: + * + *

    + *
  • Any {@link ExecutionException} has its cause wrapped in an {@link + * UncheckedExecutionException} (if the cause is an {@code Exception}) or {@link + * ExecutionError} (if the cause is an {@code Error}). + *
  • Any {@link InterruptedException} causes a retry of the {@code get} call. The interrupt is + * restored before {@code getUnchecked} returns. + *
  • Any {@link CancellationException} is propagated untouched. So is any other {@link + * RuntimeException} ({@code get} implementations are discouraged from throwing such + * exceptions). + *
+ * + *

The overall principle is to eliminate all checked exceptions: to loop to avoid {@code + * InterruptedException}, to pass through {@code CancellationException}, and to wrap any exception + * from the underlying computation in an {@code UncheckedExecutionException} or {@code + * ExecutionError}. + * + *

For an uninterruptible {@code get} that preserves other exceptions, see {@link + * Uninterruptibles#getUninterruptibly(Future)}. + * + * @throws UncheckedExecutionException if {@code get} throws an {@code ExecutionException} with an + * {@code Exception} as its cause + * @throws ExecutionError if {@code get} throws an {@code ExecutionException} with an {@code + * Error} as its cause + * @throws CancellationException if {@code get} throws a {@code CancellationException} + * @since 10.0 + */ + @CanIgnoreReturnValue + @ParametricNullness + public static V getUnchecked(Future future) { + checkNotNull(future); + try { + return getUninterruptibly(future); + } catch (ExecutionException e) { + wrapAndThrowUnchecked(e.getCause()); + throw new AssertionError(); + } + } + + private static void wrapAndThrowUnchecked(Throwable cause) { + if (cause instanceof Error) { + throw new ExecutionError((Error) cause); + } + /* + * It's an Exception. (Or it's a non-Error, non-Exception Throwable. From my survey of such + * classes, I believe that most users intended to extend Exception, so we'll treat it like an + * Exception.) + */ + throw new UncheckedExecutionException(cause); + } + + /* + * Arguably we don't need a timed getUnchecked because any operation slow enough to require a + * timeout is heavyweight enough to throw a checked exception and therefore be inappropriate to + * use with getUnchecked. Further, it's not clear that converting the checked TimeoutException to + * a RuntimeException -- especially to an UncheckedExecutionException, since it wasn't thrown by + * the computation -- makes sense, and if we don't convert it, the user still has to write a + * try-catch block. + * + * If you think you would use this method, let us know. You might also look into the + * Fork-Join framework: http://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html + */ + + // Nacho start + /** + * Registers separate success and failure callbacks to be run when the {@code Future}'s + * computation is {@linkplain java.util.concurrent.Future#isDone() complete} or, if the + * computation is already complete, immediately. + * + *

There is no guaranteed ordering of execution of callbacks, but any callback added through + * this method is guaranteed to be called once the computation is complete. + * + *

Example: + * + *

{@code
+   * ListenableFuture future = ...;
+   * addCallback(future,
+   *     new FutureCallback() {
+   *       public void onSuccess(QueryResult result) {
+   *         storeInCache(result);
+   *       }
+   *       public void onFailure(Throwable t) {
+   *         reportError(t);
+   *       }
+   *     });
+   * }
+ * + *

This overload, which does not accept an executor, uses {@code directExecutor}, a dangerous + * choice in some cases. See the discussion in the {@link ListenableFuture#addListener + * ListenableFuture.addListener} documentation. All its warnings about heavyweight listeners are + * also applicable to heavyweight callbacks passed to this method. + * + *

For a more general interface to attach a completion listener to a {@code Future}, see {@link + * ListenableFuture#addListener addListener}. + * + * @param future The future attach the callback to. + * @param callback The callback to invoke when {@code future} is completed. + * @since 10.0 + * @deprecated Use {@linkplain #addCallback(ListenableFuture, FutureCallback, Executor) the + * overload that requires an executor}. For identical behavior, pass {@link + * MoreExecutors#directExecutor}, but consider whether another executor would be safer, as + * discussed in the {@link ListenableFuture#addListener ListenableFuture.addListener} + * documentation. This method is scheduled to be removed in July 2018. + */ + @Deprecated + @com.google.errorprone.annotations.DoNotCall + public static void addCallback( + ListenableFuture future, FutureCallback callback) { + addCallback(future, callback, directExecutor()); + } + + /** + * Returns a new {@code Future} whose result is derived from the result of the given {@code + * Future}. If {@code input} fails, the returned {@code Future} fails with the same exception (and + * the function is not invoked). Example usage: + * + *

{@code
+   * ListenableFuture queryFuture = ...;
+   * ListenableFuture> rowsFuture =
+   *     transform(queryFuture, QueryResult::getRows);
+   * }
+ * + *

This overload, which does not accept an executor, uses {@code directExecutor}, a dangerous + * choice in some cases. See the discussion in the {@link ListenableFuture#addListener + * ListenableFuture.addListener} documentation. All its warnings about heavyweight listeners are + * also applicable to heavyweight functions passed to this method. + * + *

The returned {@code Future} attempts to keep its cancellation state in sync with that of the + * input future. That is, if the returned {@code Future} is cancelled, it will attempt to cancel + * the input, and if the input is cancelled, the returned {@code Future} will receive a callback + * in which it will attempt to cancel itself. + * + *

An example use of this method is to convert a serializable object returned from an RPC into + * a POJO. + * + * @param input The future to transform + * @param function A Function to transform the results of the provided future to the results of + * the returned future. This will be run in the thread that notifies input it is complete. + * @return A future that holds result of the transformation. + * @since 9.0 (in 1.0 as {@code compose}) + * @deprecated Use {@linkplain #transform(ListenableFuture, Function, Executor) the overload that + * requires an executor}. For identical behavior, pass {@link MoreExecutors#directExecutor}, + * but consider whether another executor would be safer, as discussed in the {@link + * ListenableFuture#addListener ListenableFuture.addListener} documentation. This method is + * scheduled to be removed in July 2018. + */ + @Deprecated + @com.google.errorprone.annotations.DoNotCall + public static ListenableFuture transform( + ListenableFuture input, Function function) { + return AbstractTransformFuture.create(input, function, directExecutor()); + } + + /** + * Returns a new {@code Future} whose result is asynchronously derived from the result of the + * given {@code Future}. If the given {@code Future} fails, the returned {@code Future} fails with + * the same exception (and the function is not invoked). + * + *

More precisely, the returned {@code Future} takes its result from a {@code Future} produced + * by applying the given {@code AsyncFunction} to the result of the original {@code Future}. + * Example usage: + * + *

{@code
+   * ListenableFuture rowKeyFuture = indexService.lookUp(query);
+   * ListenableFuture queryFuture =
+   *     transformAsync(rowKeyFuture, dataService::readFuture);
+   * }
+ * + *

This overload, which does not accept an executor, uses {@code directExecutor}, a dangerous + * choice in some cases. See the discussion in the {@link ListenableFuture#addListener + * ListenableFuture.addListener} documentation. All its warnings about heavyweight listeners are + * also applicable to heavyweight functions passed to this method. (Specifically, {@code + * directExecutor} functions should avoid heavyweight operations inside {@code + * AsyncFunction.apply}. Any heavyweight operations should occur in other threads responsible for + * completing the returned {@code Future}.) + * + *

The returned {@code Future} attempts to keep its cancellation state in sync with that of the + * input future and that of the future returned by the function. That is, if the returned {@code + * Future} is cancelled, it will attempt to cancel the other two, and if either of the other two + * is cancelled, the returned {@code Future} will receive a callback in which it will attempt to + * cancel itself. + * + * @param input The future to transform + * @param function A function to transform the result of the input future to the result of the + * output future + * @return A future that holds result of the function (if the input succeeded) or the original + * input's failure (if not) + * @since 19.0 (in 11.0 as {@code transform}) + * @deprecated Use {@linkplain #transformAsync(ListenableFuture, AsyncFunction, Executor) the + * overload that requires an executor}. For identical behavior, pass {@link + * MoreExecutors#directExecutor}, but consider whether another executor would be safer, as + * discussed in the {@link ListenableFuture#addListener ListenableFuture.addListener} + * documentation. This method is scheduled to be removed in July 2018. + */ + @Deprecated + @com.google.errorprone.annotations.DoNotCall + public static ListenableFuture transformAsync( + ListenableFuture input, AsyncFunction function) { + return AbstractTransformFuture.create(input, function, directExecutor()); + } + + /** + * Returns a {@code Future} whose result is taken from the given primary {@code input} or, if the + * primary input fails with the given {@code exceptionType}, from the result provided by the + * {@code fallback}. {@link Function#apply} is not invoked until the primary input has failed, so + * if the primary input succeeds, it is never invoked. If, during the invocation of {@code + * fallback}, an exception is thrown, this exception is used as the result of the output {@code + * Future}. + * + *

Usage example: + * + *

{@code
+   * ListenableFuture fetchCounterFuture = ...;
+   *
+   * // Falling back to a zero counter in case an exception happens when
+   * // processing the RPC to fetch counters.
+   * ListenableFuture faultTolerantFuture = Futures.catching(
+   *     fetchCounterFuture, FetchException.class, x -> 0);
+   * }
+ * + *

This overload, which does not accept an executor, uses {@code directExecutor}, a dangerous + * choice in some cases. See the discussion in the {@link ListenableFuture#addListener + * ListenableFuture.addListener} documentation. All its warnings about heavyweight listeners are + * also applicable to heavyweight functions passed to this method. + * + * @param input the primary input {@code Future} + * @param exceptionType the exception type that triggers use of {@code fallback}. The exception + * type is matched against the input's exception. "The input's exception" means the cause of + * the {@link ExecutionException} thrown by {@code input.get()} or, if {@code get()} throws a + * different kind of exception, that exception itself. To avoid hiding bugs and other + * unrecoverable errors, callers should prefer more specific types, avoiding {@code + * Throwable.class} in particular. + * @param fallback the {@link Function} to be called if {@code input} fails with the expected + * exception type. The function's argument is the input's exception. "The input's exception" + * means the cause of the {@link ExecutionException} thrown by {@code input.get()} or, if + * {@code get()} throws a different kind of exception, that exception itself. + * @since 19.0 + * @deprecated Use {@linkplain #catching(ListenableFuture, Class, Function, Executor) the overload + * that requires an executor}. For identical behavior, pass {@link + * MoreExecutors#directExecutor}, but consider whether another executor would be safer, as + * discussed in the {@link ListenableFuture#addListener ListenableFuture.addListener} + * documentation. This method is scheduled to be removed in July 2018. + */ + @Deprecated + @com.google.errorprone.annotations.DoNotCall + @Partially.GwtIncompatible("AVAILABLE but requires exceptionType to be Throwable.class") + public static ListenableFuture catching( + ListenableFuture input, + Class exceptionType, + Function fallback) { + return AbstractCatchingFuture.create(input, exceptionType, fallback, directExecutor()); + } + + /** + * Returns a {@code Future} whose result is taken from the given primary {@code input} or, if the + * primary input fails with the given {@code exceptionType}, from the result provided by the + * {@code fallback}. {@link AsyncFunction#apply} is not invoked until the primary input has + * failed, so if the primary input succeeds, it is never invoked. If, during the invocation of + * {@code fallback}, an exception is thrown, this exception is used as the result of the output + * {@code Future}. + * + *

Usage examples: + * + *

{@code
+   * ListenableFuture fetchCounterFuture = ...;
+   *
+   * // Falling back to a zero counter in case an exception happens when
+   * // processing the RPC to fetch counters.
+   * ListenableFuture faultTolerantFuture = Futures.catchingAsync(
+   *     fetchCounterFuture, FetchException.class, x -> immediateFuture(0));
+   * }
+ * + *

The fallback can also choose to propagate the original exception when desired: + * + *

{@code
+   * ListenableFuture fetchCounterFuture = ...;
+   *
+   * // Falling back to a zero counter only in case the exception was a
+   * // TimeoutException.
+   * ListenableFuture faultTolerantFuture = Futures.catchingAsync(
+   *     fetchCounterFuture,
+   *     FetchException.class,
+   *     e -> {
+   *       if (omitDataOnFetchFailure) {
+   *         return immediateFuture(0);
+   *       }
+   *       throw e;
+   *     });
+   * }
+ * + *

This overload, which does not accept an executor, uses {@code directExecutor}, a dangerous + * choice in some cases. See the discussion in the {@link ListenableFuture#addListener + * ListenableFuture.addListener} documentation. All its warnings about heavyweight listeners are + * also applicable to heavyweight functions passed to this method. (Specifically, {@code + * directExecutor} functions should avoid heavyweight operations inside {@code + * AsyncFunction.apply}. Any heavyweight operations should occur in other threads responsible for + * completing the returned {@code Future}.) + * + * @param input the primary input {@code Future} + * @param exceptionType the exception type that triggers use of {@code fallback}. The exception + * type is matched against the input's exception. "The input's exception" means the cause of + * the {@link ExecutionException} thrown by {@code input.get()} or, if {@code get()} throws a + * different kind of exception, that exception itself. To avoid hiding bugs and other + * unrecoverable errors, callers should prefer more specific types, avoiding {@code + * Throwable.class} in particular. + * @param fallback the {@link AsyncFunction} to be called if {@code input} fails with the expected + * exception type. The function's argument is the input's exception. "The input's exception" + * means the cause of the {@link ExecutionException} thrown by {@code input.get()} or, if + * {@code get()} throws a different kind of exception, that exception itself. + * @since 19.0 (similar functionality in 14.0 as {@code withFallback}) + * @deprecated Use {@linkplain #catchingAsync(ListenableFuture, Class, AsyncFunction, Executor) + * the overload that requires an executor}. For identical behavior, pass {@link + * MoreExecutors#directExecutor}, but consider whether another executor would be safer, as + * discussed in the {@link ListenableFuture#addListener ListenableFuture.addListener} + * documentation. This method is scheduled to be removed in July 2018. + */ + @CanIgnoreReturnValue + @Deprecated + @com.google.errorprone.annotations.DoNotCall + @Partially.GwtIncompatible("AVAILABLE but requires exceptionType to be Throwable.class") + public static ListenableFuture catchingAsync( + ListenableFuture input, + Class exceptionType, + AsyncFunction fallback) { + return AbstractCatchingFuture.create(input, exceptionType, fallback, directExecutor()); + } + // Nacho end +} diff --git a/NachoSpigot-API/src/main/java/com/google/common/util/concurrent/MoreExecutors.java b/NachoSpigot-API/src/main/java/com/google/common/util/concurrent/MoreExecutors.java new file mode 100644 index 000000000..24b84d3c7 --- /dev/null +++ b/NachoSpigot-API/src/main/java/com/google/common/util/concurrent/MoreExecutors.java @@ -0,0 +1,1172 @@ +/* + * Copyright (C) 2007 The Guava Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.common.util.concurrent; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.util.concurrent.Internal.toNanosSaturated; + +import com.google.common.annotations.Beta; +import com.google.common.annotations.GwtCompatible; +import com.google.common.annotations.GwtIncompatible; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Supplier; +import com.google.common.base.Throwables; +import com.google.common.collect.Lists; +import com.google.common.collect.Queues; +import com.google.common.util.concurrent.ForwardingListenableFuture.SimpleForwardingListenableFuture; +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import com.google.errorprone.annotations.concurrent.GuardedBy; +import java.lang.reflect.InvocationTargetException; +import java.time.Duration; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.Callable; +import java.util.concurrent.Delayed; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.checkerframework.checker.nullness.qual.Nullable; + +/** + * Factory and utility methods for {@link java.util.concurrent.Executor}, {@link ExecutorService}, + * and {@link java.util.concurrent.ThreadFactory}. + * + * @author Eric Fellheimer + * @author Kyle Littlefield + * @author Justin Mahoney + * @since 3.0 + */ +@GwtCompatible(emulated = true) +@ElementTypesAreNonnullByDefault +public final class MoreExecutors { + private MoreExecutors() {} + + /** + * Converts the given ThreadPoolExecutor into an ExecutorService that exits when the application + * is complete. It does so by using daemon threads and adding a shutdown hook to wait for their + * completion. + * + *

This is mainly for fixed thread pools. See {@link Executors#newFixedThreadPool(int)}. + * + * @param executor the executor to modify to make sure it exits when the application is finished + * @param terminationTimeout how long to wait for the executor to finish before terminating the + * JVM + * @return an unmodifiable version of the input which will not hang the JVM + * @since 28.0 + */ + @Beta + @GwtIncompatible // TODO + public static ExecutorService getExitingExecutorService( + ThreadPoolExecutor executor, Duration terminationTimeout) { + return getExitingExecutorService( + executor, toNanosSaturated(terminationTimeout), TimeUnit.NANOSECONDS); + } + + /** + * Converts the given ThreadPoolExecutor into an ExecutorService that exits when the application + * is complete. It does so by using daemon threads and adding a shutdown hook to wait for their + * completion. + * + *

This is mainly for fixed thread pools. See {@link Executors#newFixedThreadPool(int)}. + * + * @param executor the executor to modify to make sure it exits when the application is finished + * @param terminationTimeout how long to wait for the executor to finish before terminating the + * JVM + * @param timeUnit unit of time for the time parameter + * @return an unmodifiable version of the input which will not hang the JVM + */ + @Beta + @GwtIncompatible // TODO + @SuppressWarnings("GoodTime") // should accept a java.time.Duration + public static ExecutorService getExitingExecutorService( + ThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) { + return new Application().getExitingExecutorService(executor, terminationTimeout, timeUnit); + } + + /** + * Converts the given ThreadPoolExecutor into an ExecutorService that exits when the application + * is complete. It does so by using daemon threads and adding a shutdown hook to wait for their + * completion. + * + *

This method waits 120 seconds before continuing with JVM termination, even if the executor + * has not finished its work. + * + *

This is mainly for fixed thread pools. See {@link Executors#newFixedThreadPool(int)}. + * + * @param executor the executor to modify to make sure it exits when the application is finished + * @return an unmodifiable version of the input which will not hang the JVM + */ + @Beta + @GwtIncompatible // concurrency + public static ExecutorService getExitingExecutorService(ThreadPoolExecutor executor) { + return new Application().getExitingExecutorService(executor); + } + + /** + * Converts the given ScheduledThreadPoolExecutor into a ScheduledExecutorService that exits when + * the application is complete. It does so by using daemon threads and adding a shutdown hook to + * wait for their completion. + * + *

This is mainly for fixed thread pools. See {@link Executors#newScheduledThreadPool(int)}. + * + * @param executor the executor to modify to make sure it exits when the application is finished + * @param terminationTimeout how long to wait for the executor to finish before terminating the + * JVM + * @return an unmodifiable version of the input which will not hang the JVM + * @since 28.0 + */ + @Beta + @GwtIncompatible // java.time.Duration + public static ScheduledExecutorService getExitingScheduledExecutorService( + ScheduledThreadPoolExecutor executor, Duration terminationTimeout) { + return getExitingScheduledExecutorService( + executor, toNanosSaturated(terminationTimeout), TimeUnit.NANOSECONDS); + } + + /** + * Converts the given ScheduledThreadPoolExecutor into a ScheduledExecutorService that exits when + * the application is complete. It does so by using daemon threads and adding a shutdown hook to + * wait for their completion. + * + *

This is mainly for fixed thread pools. See {@link Executors#newScheduledThreadPool(int)}. + * + * @param executor the executor to modify to make sure it exits when the application is finished + * @param terminationTimeout how long to wait for the executor to finish before terminating the + * JVM + * @param timeUnit unit of time for the time parameter + * @return an unmodifiable version of the input which will not hang the JVM + */ + @Beta + @GwtIncompatible // TODO + @SuppressWarnings("GoodTime") // should accept a java.time.Duration + public static ScheduledExecutorService getExitingScheduledExecutorService( + ScheduledThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) { + return new Application() + .getExitingScheduledExecutorService(executor, terminationTimeout, timeUnit); + } + + /** + * Converts the given ScheduledThreadPoolExecutor into a ScheduledExecutorService that exits when + * the application is complete. It does so by using daemon threads and adding a shutdown hook to + * wait for their completion. + * + *

This method waits 120 seconds before continuing with JVM termination, even if the executor + * has not finished its work. + * + *

This is mainly for fixed thread pools. See {@link Executors#newScheduledThreadPool(int)}. + * + * @param executor the executor to modify to make sure it exits when the application is finished + * @return an unmodifiable version of the input which will not hang the JVM + */ + @Beta + @GwtIncompatible // TODO + public static ScheduledExecutorService getExitingScheduledExecutorService( + ScheduledThreadPoolExecutor executor) { + return new Application().getExitingScheduledExecutorService(executor); + } + + /** + * Add a shutdown hook to wait for thread completion in the given {@link ExecutorService service}. + * This is useful if the given service uses daemon threads, and we want to keep the JVM from + * exiting immediately on shutdown, instead giving these daemon threads a chance to terminate + * normally. + * + * @param service ExecutorService which uses daemon threads + * @param terminationTimeout how long to wait for the executor to finish before terminating the + * JVM + * @since 28.0 + */ + @Beta + @GwtIncompatible // java.time.Duration + public static void addDelayedShutdownHook(ExecutorService service, Duration terminationTimeout) { + addDelayedShutdownHook(service, toNanosSaturated(terminationTimeout), TimeUnit.NANOSECONDS); + } + + /** + * Add a shutdown hook to wait for thread completion in the given {@link ExecutorService service}. + * This is useful if the given service uses daemon threads, and we want to keep the JVM from + * exiting immediately on shutdown, instead giving these daemon threads a chance to terminate + * normally. + * + * @param service ExecutorService which uses daemon threads + * @param terminationTimeout how long to wait for the executor to finish before terminating the + * JVM + * @param timeUnit unit of time for the time parameter + */ + @Beta + @GwtIncompatible // TODO + @SuppressWarnings("GoodTime") // should accept a java.time.Duration + public static void addDelayedShutdownHook( + ExecutorService service, long terminationTimeout, TimeUnit timeUnit) { + new Application().addDelayedShutdownHook(service, terminationTimeout, timeUnit); + } + + /** Represents the current application to register shutdown hooks. */ + @GwtIncompatible // TODO + @VisibleForTesting + static class Application { + + final ExecutorService getExitingExecutorService( + ThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) { + useDaemonThreadFactory(executor); + ExecutorService service = Executors.unconfigurableExecutorService(executor); + addDelayedShutdownHook(executor, terminationTimeout, timeUnit); + return service; + } + + final ExecutorService getExitingExecutorService(ThreadPoolExecutor executor) { + return getExitingExecutorService(executor, 120, TimeUnit.SECONDS); + } + + final ScheduledExecutorService getExitingScheduledExecutorService( + ScheduledThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) { + useDaemonThreadFactory(executor); + ScheduledExecutorService service = Executors.unconfigurableScheduledExecutorService(executor); + addDelayedShutdownHook(executor, terminationTimeout, timeUnit); + return service; + } + + final ScheduledExecutorService getExitingScheduledExecutorService( + ScheduledThreadPoolExecutor executor) { + return getExitingScheduledExecutorService(executor, 120, TimeUnit.SECONDS); + } + + final void addDelayedShutdownHook( + final ExecutorService service, final long terminationTimeout, final TimeUnit timeUnit) { + checkNotNull(service); + checkNotNull(timeUnit); + addShutdownHook( + MoreExecutors.newThread( + "DelayedShutdownHook-for-" + service, + new Runnable() { + @Override + public void run() { + try { + // We'd like to log progress and failures that may arise in the + // following code, but unfortunately the behavior of logging + // is undefined in shutdown hooks. + // This is because the logging code installs a shutdown hook of its + // own. See Cleaner class inside {@link LogManager}. + service.shutdown(); + service.awaitTermination(terminationTimeout, timeUnit); + } catch (InterruptedException ignored) { + // We're shutting down anyway, so just ignore. + } + } + })); + } + + @VisibleForTesting + void addShutdownHook(Thread hook) { + Runtime.getRuntime().addShutdownHook(hook); + } + } + + @GwtIncompatible // TODO + private static void useDaemonThreadFactory(ThreadPoolExecutor executor) { + executor.setThreadFactory( + new ThreadFactoryBuilder() + .setDaemon(true) + .setThreadFactory(executor.getThreadFactory()) + .build()); + } + + // See newDirectExecutorService javadoc for behavioral notes. + @GwtIncompatible // TODO + private static final class DirectExecutorService extends AbstractListeningExecutorService { + /** Lock used whenever accessing the state variables (runningTasks, shutdown) of the executor */ + private final Object lock = new Object(); + + /* + * Conceptually, these two variables describe the executor being in + * one of three states: + * - Active: shutdown == false + * - Shutdown: runningTasks > 0 and shutdown == true + * - Terminated: runningTasks == 0 and shutdown == true + */ + @GuardedBy("lock") + private int runningTasks = 0; + + @GuardedBy("lock") + private boolean shutdown = false; + + @Override + public void execute(Runnable command) { + startTask(); + try { + command.run(); + } finally { + endTask(); + } + } + + @Override + public boolean isShutdown() { + synchronized (lock) { + return shutdown; + } + } + + @Override + public void shutdown() { + synchronized (lock) { + shutdown = true; + if (runningTasks == 0) { + lock.notifyAll(); + } + } + } + + // See newDirectExecutorService javadoc for unusual behavior of this method. + @Override + public List shutdownNow() { + shutdown(); + return Collections.emptyList(); + } + + @Override + public boolean isTerminated() { + synchronized (lock) { + return shutdown && runningTasks == 0; + } + } + + @Override + public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { + long nanos = unit.toNanos(timeout); + synchronized (lock) { + while (true) { + if (shutdown && runningTasks == 0) { + return true; + } else if (nanos <= 0) { + return false; + } else { + long now = System.nanoTime(); + TimeUnit.NANOSECONDS.timedWait(lock, nanos); + nanos -= System.nanoTime() - now; // subtract the actual time we waited + } + } + } + } + + /** + * Checks if the executor has been shut down and increments the running task count. + * + * @throws RejectedExecutionException if the executor has been previously shutdown + */ + private void startTask() { + synchronized (lock) { + if (shutdown) { + throw new RejectedExecutionException("Executor already shutdown"); + } + runningTasks++; + } + } + + /** Decrements the running task count. */ + private void endTask() { + synchronized (lock) { + int numRunning = --runningTasks; + if (numRunning == 0) { + lock.notifyAll(); + } + } + } + } + + /** + * Creates an executor service that runs each task in the thread that invokes {@code + * execute/submit}, as in {@code ThreadPoolExecutor.CallerRunsPolicy}. This applies both to + * individually submitted tasks and to collections of tasks submitted via {@code invokeAll} or + * {@code invokeAny}. In the latter case, tasks will run serially on the calling thread. Tasks are + * run to completion before a {@code Future} is returned to the caller (unless the executor has + * been shutdown). + * + *

Although all tasks are immediately executed in the thread that submitted the task, this + * {@code ExecutorService} imposes a small locking overhead on each task submission in order to + * implement shutdown and termination behavior. + * + *

The implementation deviates from the {@code ExecutorService} specification with regards to + * the {@code shutdownNow} method. First, "best-effort" with regards to canceling running tasks is + * implemented as "no-effort". No interrupts or other attempts are made to stop threads executing + * tasks. Second, the returned list will always be empty, as any submitted task is considered to + * have started execution. This applies also to tasks given to {@code invokeAll} or {@code + * invokeAny} which are pending serial execution, even the subset of the tasks that have not yet + * started execution. It is unclear from the {@code ExecutorService} specification if these should + * be included, and it's much easier to implement the interpretation that they not be. Finally, a + * call to {@code shutdown} or {@code shutdownNow} may result in concurrent calls to {@code + * invokeAll/invokeAny} throwing RejectedExecutionException, although a subset of the tasks may + * already have been executed. + * + * @since 18.0 (present as MoreExecutors.sameThreadExecutor() since 10.0) + */ + @GwtIncompatible // TODO + public static ListeningExecutorService newDirectExecutorService() { + return new DirectExecutorService(); + } + + /** + * Returns an {@link Executor} that runs each task in the thread that invokes {@link + * Executor#execute execute}, as in {@code ThreadPoolExecutor.CallerRunsPolicy}. + * + *

This executor is appropriate for tasks that are lightweight and not deeply chained. + * Inappropriate {@code directExecutor} usage can cause problems, and these problems can be + * difficult to reproduce because they depend on timing. For example: + * + *

    + *
  • A call like {@code future.transform(function, directExecutor())} may execute the function + * immediately in the thread that is calling {@code transform}. (This specific case happens + * if the future is already completed.) If {@code transform} call was made from a UI thread + * or other latency-sensitive thread, a heavyweight function can harm responsiveness. + *
  • If the task will be executed later, consider which thread will trigger the execution -- + * since that thread will execute the task inline. If the thread is a shared system thread + * like an RPC network thread, a heavyweight task can stall progress of the whole system or + * even deadlock it. + *
  • If many tasks will be triggered by the same event, one heavyweight task may delay other + * tasks -- even tasks that are not themselves {@code directExecutor} tasks. + *
  • If many such tasks are chained together (such as with {@code + * future.transform(...).transform(...).transform(...)....}), they may overflow the stack. + * (In simple cases, callers can avoid this by registering all tasks with the same {@link + * MoreExecutors#newSequentialExecutor} wrapper around {@code directExecutor()}. More + * complex cases may require using thread pools or making deeper changes.) + *
  • If an exception propagates out of a {@code Runnable}, it is not necessarily seen by any + * {@code UncaughtExceptionHandler} for the thread. For example, if the callback passed to + * {@link Futures#addCallback} throws an exception, that exception will be typically be + * logged by the {@link ListenableFuture} implementation, even if the thread is configured + * to do something different. In other cases, no code will catch the exception, and it may + * terminate whichever thread happens to trigger the execution. + *
+ * + * Additionally, beware of executing tasks with {@code directExecutor} while holding a lock. Since + * the task you submit to the executor (or any other arbitrary work the executor does) may do slow + * work or acquire other locks, you risk deadlocks. + * + *

This instance is equivalent to: + * + *

{@code
+     * final class DirectExecutor implements Executor {
+     *   public void execute(Runnable r) {
+     *     r.run();
+     *   }
+     * }
+     * }
+ * + *

This should be preferred to {@link #newDirectExecutorService()} because implementing the + * {@link ExecutorService} subinterface necessitates significant performance overhead. + * + * @since 18.0 + */ + public static Executor directExecutor() { + return DirectExecutor.INSTANCE; + } + + /** + * Returns an {@link Executor} that runs each task executed sequentially, such that no two tasks + * are running concurrently. Submitted tasks have a happens-before order as defined in the Java + * Language Specification. + * + *

The executor uses {@code delegate} in order to {@link Executor#execute execute} each task in + * turn, and does not create any threads of its own. + * + *

After execution begins on a thread from the {@code delegate} {@link Executor}, tasks are + * polled and executed from a task queue until there are no more tasks. The thread will not be + * released until there are no more tasks to run. + * + *

If a task is submitted while a thread is executing tasks from the task queue, the thread + * will not be released until that submitted task is also complete. + * + *

If a task is {@linkplain Thread#interrupt interrupted} while a task is running: + * + *

    + *
  1. execution will not stop until the task queue is empty. + *
  2. tasks will begin execution with the thread marked as not interrupted - any interruption + * applies only to the task that was running at the point of interruption. + *
  3. if the thread was interrupted before the SequentialExecutor's worker begins execution, + * the interrupt will be restored to the thread after it completes so that its {@code + * delegate} Executor may process the interrupt. + *
  4. subtasks are run with the thread uninterrupted and interrupts received during execution + * of a task are ignored. + *
+ * + *

{@code RuntimeException}s thrown by tasks are simply logged and the executor keeps trucking. + * If an {@code Error} is thrown, the error will propagate and execution will stop until the next + * time a task is submitted. + * + *

When an {@code Error} is thrown by an executed task, previously submitted tasks may never + * run. An attempt will be made to restart execution on the next call to {@code execute}. If the + * {@code delegate} has begun to reject execution, the previously submitted tasks may never run, + * despite not throwing a RejectedExecutionException synchronously with the call to {@code + * execute}. If this behaviour is problematic, use an Executor with a single thread (e.g. {@link + * Executors#newSingleThreadExecutor}). + * + * @since 23.3 (since 23.1 as {@code sequentialExecutor}) + */ + @Beta + @GwtIncompatible + public static Executor newSequentialExecutor(Executor delegate) { + return new SequentialExecutor(delegate); + } + + /** + * Creates an {@link ExecutorService} whose {@code submit} and {@code invokeAll} methods submit + * {@link ListenableFutureTask} instances to the given delegate executor. Those methods, as well + * as {@code execute} and {@code invokeAny}, are implemented in terms of calls to {@code + * delegate.execute}. All other methods are forwarded unchanged to the delegate. This implies that + * the returned {@code ListeningExecutorService} never calls the delegate's {@code submit}, {@code + * invokeAll}, and {@code invokeAny} methods, so any special handling of tasks must be implemented + * in the delegate's {@code execute} method or by wrapping the returned {@code + * ListeningExecutorService}. + * + *

If the delegate executor was already an instance of {@code ListeningExecutorService}, it is + * returned untouched, and the rest of this documentation does not apply. + * + * @since 10.0 + */ + @GwtIncompatible // TODO + public static ListeningExecutorService listeningDecorator(ExecutorService delegate) { + return (delegate instanceof ListeningExecutorService) + ? (ListeningExecutorService) delegate + : (delegate instanceof ScheduledExecutorService) + ? new ScheduledListeningDecorator((ScheduledExecutorService) delegate) + : new ListeningDecorator(delegate); + } + + /** + * Creates a {@link ScheduledExecutorService} whose {@code submit} and {@code invokeAll} methods + * submit {@link ListenableFutureTask} instances to the given delegate executor. Those methods, as + * well as {@code execute} and {@code invokeAny}, are implemented in terms of calls to {@code + * delegate.execute}. All other methods are forwarded unchanged to the delegate. This implies that + * the returned {@code ListeningScheduledExecutorService} never calls the delegate's {@code + * submit}, {@code invokeAll}, and {@code invokeAny} methods, so any special handling of tasks + * must be implemented in the delegate's {@code execute} method or by wrapping the returned {@code + * ListeningScheduledExecutorService}. + * + *

If the delegate executor was already an instance of {@code + * ListeningScheduledExecutorService}, it is returned untouched, and the rest of this + * documentation does not apply. + * + * @since 10.0 + */ + @GwtIncompatible // TODO + public static ListeningScheduledExecutorService listeningDecorator( + ScheduledExecutorService delegate) { + return (delegate instanceof ListeningScheduledExecutorService) + ? (ListeningScheduledExecutorService) delegate + : new ScheduledListeningDecorator(delegate); + } + + @GwtIncompatible // TODO + private static class ListeningDecorator extends AbstractListeningExecutorService { + private final ExecutorService delegate; + + ListeningDecorator(ExecutorService delegate) { + this.delegate = checkNotNull(delegate); + } + + @Override + public final boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { + return delegate.awaitTermination(timeout, unit); + } + + @Override + public final boolean isShutdown() { + return delegate.isShutdown(); + } + + @Override + public final boolean isTerminated() { + return delegate.isTerminated(); + } + + @Override + public final void shutdown() { + delegate.shutdown(); + } + + @Override + public final List shutdownNow() { + return delegate.shutdownNow(); + } + + @Override + public final void execute(Runnable command) { + delegate.execute(command); + } + + @Override + public final String toString() { + return super.toString() + "[" + delegate + "]"; + } + } + + @GwtIncompatible // TODO + private static final class ScheduledListeningDecorator extends ListeningDecorator + implements ListeningScheduledExecutorService { + @SuppressWarnings("hiding") + final ScheduledExecutorService delegate; + + ScheduledListeningDecorator(ScheduledExecutorService delegate) { + super(delegate); + this.delegate = checkNotNull(delegate); + } + + @Override + public ListenableScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { + TrustedListenableFutureTask<@Nullable Void> task = + TrustedListenableFutureTask.create(command, null); + ScheduledFuture scheduled = delegate.schedule(task, delay, unit); + return new ListenableScheduledTask<@Nullable Void>(task, scheduled); + } + + @Override + public ListenableScheduledFuture schedule( + Callable callable, long delay, TimeUnit unit) { + TrustedListenableFutureTask task = TrustedListenableFutureTask.create(callable); + ScheduledFuture scheduled = delegate.schedule(task, delay, unit); + return new ListenableScheduledTask(task, scheduled); + } + + @Override + public ListenableScheduledFuture scheduleAtFixedRate( + Runnable command, long initialDelay, long period, TimeUnit unit) { + NeverSuccessfulListenableFutureTask task = new NeverSuccessfulListenableFutureTask(command); + ScheduledFuture scheduled = delegate.scheduleAtFixedRate(task, initialDelay, period, unit); + return new ListenableScheduledTask<@Nullable Void>(task, scheduled); + } + + @Override + public ListenableScheduledFuture scheduleWithFixedDelay( + Runnable command, long initialDelay, long delay, TimeUnit unit) { + NeverSuccessfulListenableFutureTask task = new NeverSuccessfulListenableFutureTask(command); + ScheduledFuture scheduled = + delegate.scheduleWithFixedDelay(task, initialDelay, delay, unit); + return new ListenableScheduledTask<@Nullable Void>(task, scheduled); + } + + private static final class ListenableScheduledTask + extends SimpleForwardingListenableFuture implements ListenableScheduledFuture { + + private final ScheduledFuture scheduledDelegate; + + public ListenableScheduledTask( + ListenableFuture listenableDelegate, ScheduledFuture scheduledDelegate) { + super(listenableDelegate); + this.scheduledDelegate = scheduledDelegate; + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + boolean cancelled = super.cancel(mayInterruptIfRunning); + if (cancelled) { + // Unless it is cancelled, the delegate may continue being scheduled + scheduledDelegate.cancel(mayInterruptIfRunning); + + // TODO(user): Cancel "this" if "scheduledDelegate" is cancelled. + } + return cancelled; + } + + @Override + public long getDelay(TimeUnit unit) { + return scheduledDelegate.getDelay(unit); + } + + @Override + public int compareTo(Delayed other) { + return scheduledDelegate.compareTo(other); + } + } + + @GwtIncompatible // TODO + private static final class NeverSuccessfulListenableFutureTask + extends AbstractFuture.TrustedFuture<@Nullable Void> implements Runnable { + private final Runnable delegate; + + public NeverSuccessfulListenableFutureTask(Runnable delegate) { + this.delegate = checkNotNull(delegate); + } + + @Override + public void run() { + try { + delegate.run(); + } catch (Throwable t) { + setException(t); + throw Throwables.propagate(t); + } + } + + @Override + protected String pendingToString() { + return "task=[" + delegate + "]"; + } + } + } + + /* + * This following method is a modified version of one found in + * http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/test/tck/AbstractExecutorServiceTest.java?revision=1.30 + * which contained the following notice: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 Expert Group and released to + * the public domain, as explained at http://creativecommons.org/publicdomain/zero/1.0/ + * + * Other contributors include Andrew Wright, Jeffrey Hayes, Pat Fisher, Mike Judd. + */ + + /** + * An implementation of {@link ExecutorService#invokeAny} for {@link ListeningExecutorService} + * implementations. + */ + @GwtIncompatible + @ParametricNullness + static T invokeAnyImpl( + ListeningExecutorService executorService, + Collection> tasks, + boolean timed, + Duration timeout) + throws InterruptedException, ExecutionException, TimeoutException { + return invokeAnyImpl( + executorService, tasks, timed, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); + } + + /** + * An implementation of {@link ExecutorService#invokeAny} for {@link ListeningExecutorService} + * implementations. + */ + @SuppressWarnings("GoodTime") // should accept a java.time.Duration + @GwtIncompatible + @ParametricNullness + static T invokeAnyImpl( + ListeningExecutorService executorService, + Collection> tasks, + boolean timed, + long timeout, + TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + checkNotNull(executorService); + checkNotNull(unit); + int ntasks = tasks.size(); + checkArgument(ntasks > 0); + List> futures = Lists.newArrayListWithCapacity(ntasks); + BlockingQueue> futureQueue = Queues.newLinkedBlockingQueue(); + long timeoutNanos = unit.toNanos(timeout); + + // For efficiency, especially in executors with limited + // parallelism, check to see if previously submitted tasks are + // done before submitting more of them. This interleaving + // plus the exception mechanics account for messiness of main + // loop. + + try { + // Record exceptions so that if we fail to obtain any + // result, we can throw the last exception we got. + ExecutionException ee = null; + long lastTime = timed ? System.nanoTime() : 0; + Iterator> it = tasks.iterator(); + + futures.add(submitAndAddQueueListener(executorService, it.next(), futureQueue)); + --ntasks; + int active = 1; + + while (true) { + Future f = futureQueue.poll(); + if (f == null) { + if (ntasks > 0) { + --ntasks; + futures.add(submitAndAddQueueListener(executorService, it.next(), futureQueue)); + ++active; + } else if (active == 0) { + break; + } else if (timed) { + f = futureQueue.poll(timeoutNanos, TimeUnit.NANOSECONDS); + if (f == null) { + throw new TimeoutException(); + } + long now = System.nanoTime(); + timeoutNanos -= now - lastTime; + lastTime = now; + } else { + f = futureQueue.take(); + } + } + if (f != null) { + --active; + try { + return f.get(); + } catch (ExecutionException eex) { + ee = eex; + } catch (RuntimeException rex) { + ee = new ExecutionException(rex); + } + } + } + + if (ee == null) { + ee = new ExecutionException(null); + } + throw ee; + } finally { + for (Future f : futures) { + f.cancel(true); + } + } + } + + /** + * Submits the task and adds a listener that adds the future to {@code queue} when it completes. + */ + @GwtIncompatible // TODO + private static ListenableFuture submitAndAddQueueListener( + ListeningExecutorService executorService, + Callable task, + final BlockingQueue> queue) { + final ListenableFuture future = executorService.submit(task); + future.addListener( + new Runnable() { + @Override + public void run() { + queue.add(future); + } + }, + directExecutor()); + return future; + } + + /** + * Returns a default thread factory used to create new threads. + * + *

When running on AppEngine with access to AppEngine legacy + * APIs, this method returns {@code ThreadManager.currentRequestThreadFactory()}. Otherwise, + * it returns {@link Executors#defaultThreadFactory()}. + * + * @since 14.0 + */ + @Beta + @GwtIncompatible // concurrency + public static ThreadFactory platformThreadFactory() { + if (!isAppEngineWithApiClasses()) { + return Executors.defaultThreadFactory(); + } + try { + return (ThreadFactory) + Class.forName("com.google.appengine.api.ThreadManager") + .getMethod("currentRequestThreadFactory") + .invoke(null); + /* + * Do not merge the 3 catch blocks below. javac would infer a type of + * ReflectiveOperationException, which Animal Sniffer would reject. (Old versions of Android + * don't *seem* to mind, but there might be edge cases of which we're unaware.) + */ + } catch (IllegalAccessException e) { + throw new RuntimeException("Couldn't invoke ThreadManager.currentRequestThreadFactory", e); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Couldn't invoke ThreadManager.currentRequestThreadFactory", e); + } catch (NoSuchMethodException e) { + throw new RuntimeException("Couldn't invoke ThreadManager.currentRequestThreadFactory", e); + } catch (InvocationTargetException e) { + throw Throwables.propagate(e.getCause()); + } + } + + @GwtIncompatible // TODO + private static boolean isAppEngineWithApiClasses() { + if (System.getProperty("com.google.appengine.runtime.environment") == null) { + return false; + } + try { + Class.forName("com.google.appengine.api.utils.SystemProperty"); + } catch (ClassNotFoundException e) { + return false; + } + try { + // If the current environment is null, we're not inside AppEngine. + return Class.forName("com.google.apphosting.api.ApiProxy") + .getMethod("getCurrentEnvironment") + .invoke(null) + != null; + } catch (ClassNotFoundException e) { + // If ApiProxy doesn't exist, we're not on AppEngine at all. + return false; + } catch (InvocationTargetException e) { + // If ApiProxy throws an exception, we're not in a proper AppEngine environment. + return false; + } catch (IllegalAccessException e) { + // If the method isn't accessible, we're not on a supported version of AppEngine; + return false; + } catch (NoSuchMethodException e) { + // If the method doesn't exist, we're not on a supported version of AppEngine; + return false; + } + } + + /** + * Creates a thread using {@link #platformThreadFactory}, and sets its name to {@code name} unless + * changing the name is forbidden by the security manager. + */ + @GwtIncompatible // concurrency + static Thread newThread(String name, Runnable runnable) { + checkNotNull(name); + checkNotNull(runnable); + Thread result = platformThreadFactory().newThread(runnable); + try { + result.setName(name); + } catch (SecurityException e) { + // OK if we can't set the name in this environment. + } + return result; + } + + // TODO(lukes): provide overloads for ListeningExecutorService? ListeningScheduledExecutorService? + // TODO(lukes): provide overloads that take constant strings? Functions to + // calculate names? + + /** + * Creates an {@link Executor} that renames the {@link Thread threads} that its tasks run in. + * + *

The names are retrieved from the {@code nameSupplier} on the thread that is being renamed + * right before each task is run. The renaming is best effort, if a {@link SecurityManager} + * prevents the renaming then it will be skipped but the tasks will still execute. + * + * @param executor The executor to decorate + * @param nameSupplier The source of names for each task + */ + @GwtIncompatible // concurrency + static Executor renamingDecorator(final Executor executor, final Supplier nameSupplier) { + checkNotNull(executor); + checkNotNull(nameSupplier); + return new Executor() { + @Override + public void execute(Runnable command) { + executor.execute(Callables.threadRenaming(command, nameSupplier)); + } + }; + } + + /** + * Creates an {@link ExecutorService} that renames the {@link Thread threads} that its tasks run + * in. + * + *

The names are retrieved from the {@code nameSupplier} on the thread that is being renamed + * right before each task is run. The renaming is best effort, if a {@link SecurityManager} + * prevents the renaming then it will be skipped but the tasks will still execute. + * + * @param service The executor to decorate + * @param nameSupplier The source of names for each task + */ + @GwtIncompatible // concurrency + static ExecutorService renamingDecorator( + final ExecutorService service, final Supplier nameSupplier) { + checkNotNull(service); + checkNotNull(nameSupplier); + return new WrappingExecutorService(service) { + @Override + protected Callable wrapTask(Callable callable) { + return Callables.threadRenaming(callable, nameSupplier); + } + + @Override + protected Runnable wrapTask(Runnable command) { + return Callables.threadRenaming(command, nameSupplier); + } + }; + } + + /** + * Creates a {@link ScheduledExecutorService} that renames the {@link Thread threads} that its + * tasks run in. + * + *

The names are retrieved from the {@code nameSupplier} on the thread that is being renamed + * right before each task is run. The renaming is best effort, if a {@link SecurityManager} + * prevents the renaming then it will be skipped but the tasks will still execute. + * + * @param service The executor to decorate + * @param nameSupplier The source of names for each task + */ + @GwtIncompatible // concurrency + static ScheduledExecutorService renamingDecorator( + final ScheduledExecutorService service, final Supplier nameSupplier) { + checkNotNull(service); + checkNotNull(nameSupplier); + return new WrappingScheduledExecutorService(service) { + @Override + protected Callable wrapTask(Callable callable) { + return Callables.threadRenaming(callable, nameSupplier); + } + + @Override + protected Runnable wrapTask(Runnable command) { + return Callables.threadRenaming(command, nameSupplier); + } + }; + } + + /** + * Shuts down the given executor service gradually, first disabling new submissions and later, if + * necessary, cancelling remaining tasks. + * + *

The method takes the following steps: + * + *

    + *
  1. calls {@link ExecutorService#shutdown()}, disabling acceptance of new submitted tasks. + *
  2. awaits executor service termination for half of the specified timeout. + *
  3. if the timeout expires, it calls {@link ExecutorService#shutdownNow()}, cancelling + * pending tasks and interrupting running tasks. + *
  4. awaits executor service termination for the other half of the specified timeout. + *
+ * + *

If, at any step of the process, the calling thread is interrupted, the method calls {@link + * ExecutorService#shutdownNow()} and returns. + * + * @param service the {@code ExecutorService} to shut down + * @param timeout the maximum time to wait for the {@code ExecutorService} to terminate + * @return {@code true} if the {@code ExecutorService} was terminated successfully, {@code false} + * if the call timed out or was interrupted + * @since 28.0 + */ + @Beta + @CanIgnoreReturnValue + @GwtIncompatible // java.time.Duration + public static boolean shutdownAndAwaitTermination(ExecutorService service, Duration timeout) { + return shutdownAndAwaitTermination(service, toNanosSaturated(timeout), TimeUnit.NANOSECONDS); + } + + /** + * Shuts down the given executor service gradually, first disabling new submissions and later, if + * necessary, cancelling remaining tasks. + * + *

The method takes the following steps: + * + *

    + *
  1. calls {@link ExecutorService#shutdown()}, disabling acceptance of new submitted tasks. + *
  2. awaits executor service termination for half of the specified timeout. + *
  3. if the timeout expires, it calls {@link ExecutorService#shutdownNow()}, cancelling + * pending tasks and interrupting running tasks. + *
  4. awaits executor service termination for the other half of the specified timeout. + *
+ * + *

If, at any step of the process, the calling thread is interrupted, the method calls {@link + * ExecutorService#shutdownNow()} and returns. + * + * @param service the {@code ExecutorService} to shut down + * @param timeout the maximum time to wait for the {@code ExecutorService} to terminate + * @param unit the time unit of the timeout argument + * @return {@code true} if the {@code ExecutorService} was terminated successfully, {@code false} + * if the call timed out or was interrupted + * @since 17.0 + */ + @Beta + @CanIgnoreReturnValue + @GwtIncompatible // concurrency + @SuppressWarnings("GoodTime") // should accept a java.time.Duration + public static boolean shutdownAndAwaitTermination( + ExecutorService service, long timeout, TimeUnit unit) { + long halfTimeoutNanos = unit.toNanos(timeout) / 2; + // Disable new tasks from being submitted + service.shutdown(); + try { + // Wait for half the duration of the timeout for existing tasks to terminate + if (!service.awaitTermination(halfTimeoutNanos, TimeUnit.NANOSECONDS)) { + // Cancel currently executing tasks + service.shutdownNow(); + // Wait the other half of the timeout for tasks to respond to being cancelled + service.awaitTermination(halfTimeoutNanos, TimeUnit.NANOSECONDS); + } + } catch (InterruptedException ie) { + // Preserve interrupt status + Thread.currentThread().interrupt(); + // (Re-)Cancel if current thread also interrupted + service.shutdownNow(); + } + return service.isTerminated(); + } + + /** + * Returns an Executor that will propagate {@link RejectedExecutionException} from the delegate + * executor to the given {@code future}. + * + *

Note, the returned executor can only be used once. + */ + static Executor rejectionPropagatingExecutor( + final Executor delegate, final AbstractFuture future) { + checkNotNull(delegate); + checkNotNull(future); + if (delegate == directExecutor()) { + // directExecutor() cannot throw RejectedExecutionException + return delegate; + } + return new Executor() { + @Override + public void execute(Runnable command) { + try { + delegate.execute(command); + } catch (RejectedExecutionException e) { + future.setException(e); + } + } + }; + } + + // Nacho start + /** + * Creates an executor service that runs each task in the thread that invokes {@code + * execute/submit}, as in {@code ThreadPoolExecutor.CallerRunsPolicy}. This applies both to + * individually submitted tasks and to collections of tasks submitted via {@code invokeAll} or + * {@code invokeAny}. In the latter case, tasks will run serially on the calling thread. Tasks are + * run to completion before a {@code Future} is returned to the caller (unless the executor has + * been shutdown). + * + *

Although all tasks are immediately executed in the thread that submitted the task, this + * {@code ExecutorService} imposes a small locking overhead on each task submission in order to + * implement shutdown and termination behavior. + * + *

The implementation deviates from the {@code ExecutorService} specification with regards to + * the {@code shutdownNow} method. First, "best-effort" with regards to canceling running tasks is + * implemented as "no-effort". No interrupts or other attempts are made to stop threads executing + * tasks. Second, the returned list will always be empty, as any submitted task is considered to + * have started execution. This applies also to tasks given to {@code invokeAll} or {@code + * invokeAny} which are pending serial execution, even the subset of the tasks that have not yet + * started execution. It is unclear from the {@code ExecutorService} specification if these should + * be included, and it's much easier to implement the interpretation that they not be. Finally, a + * call to {@code shutdown} or {@code shutdownNow} may result in concurrent calls to {@code + * invokeAll/invokeAny} throwing RejectedExecutionException, although a subset of the tasks may + * already have been executed. + * + * @since 10.0 + * @deprecated replaced by {@link MoreExecutors#sameThreadExecutor()} + * @see MoreExecutors#sameThreadExecutor() + */ + @Deprecated + @GwtIncompatible + public static ListeningExecutorService sameThreadExecutor() { + return newDirectExecutorService(); + } + // Nacho end +} \ No newline at end of file