Class RestAction<T>

  • Type Parameters:
    T - The generic response type for this RestAction
    Direct Known Subclasses:
    ApplicationAction, AuditableRestAction, GuildAction, MemberAction, MessageAction, MessageHistory.MessageRetrieveAction, OrderAction, PaginationAction, RestAction.EmptyRestAction

    public abstract class RestAction<T>
    extends java.lang.Object
    A class representing a terminal between the user and the discord API.
    This is used to offer users the ability to decide how JDA should limit a Request.

    Methods that return an instance of RestAction require an additional step to complete the execution. Thus the user needs to append a follow-up method.

    A default RestAction is issued with the following operations:

    • queue(), queue(Consumer), queue(Consumer, Consumer)
      The fastest and most simplistic way to execute a RestAction is to queue it.
      This method has two optional callback functions, one with the generic type and another with a failure exception.
    • submit(), submit(boolean)
      Provides a Future representing the pending request.
      An optional parameter of type boolean can be passed to disable automated rate limit handling. (not recommended)
    • complete(), complete(boolean)
      Blocking execution building up on submit().
      This will simply block the thread and return the Request result, or throw an exception.
      An optional parameter of type boolean can be passed to disable automated rate limit handling. (not recommended)
    The most efficient way to use a RestAction is by using the asynchronous queue() operations.
    These allow users to provide success and failure callbacks which will be called at a convenient time.

    Planning Execution

    To schedule a RestAction we provide both queue() and complete() versions that will be executed by a ScheduledExecutorService after a specified delay:
    • queueAfter(long, TimeUnit)
      Schedules a call to queue() with default callback Consumers to be executed after the specified delay.
      The TimeUnit is used to convert the provided long into a delay time.
      Example: queueAfter(1, TimeUnit.SECONDS);
      will call queue() 1 second later.
    • submitAfter(long, TimeUnit)
      This returns a ScheduledFuture which can be joined into the current Thread using Future.get()
      The blocking call to submitAfter(delay, unit).get() will return the value processed by a call to complete()
    • completeAfter(long, TimeUnit)
      This operation simply sleeps for the given delay and will call complete() once finished sleeping.

    All of those operations provide overloads for optional parameters such as a custom ScheduledExecutorService instead of using the default global JDA executor. Specifically queueAfter(long, TimeUnit) has overloads to provide a success and/or failure callback due to the returned ScheduledFuture not being able to provide the response values of the queue() callbacks.

    Using RestActions

    The most common way to use a RestAction is not using the returned value.
    For instance sending messages usually means you will not require to view the message once it was sent. Thus we can simply use the asynchronous queue() operation which will be executed on a rate limit worker thread in the background, without blocking your current thread:
    
          MessageChannel channel = event.getChannel();
         RestAction<Message> action = channel.sendMessage("Hello World");
          action.queue(); // Execute the rest action asynchronously
     

    Sometimes it is important to access the response value, possibly to modify it later.
    Now we have two options to actually access the response value, either using an asynchronous callback Consumer or the (not recommended) complete() which will block the current thread until the response has been processed and joins with the current thread.

    Example Queue: (recommended)

    
         MessageChannel channel = event.getChannel();
         final long time = System.currentTimeMillis();
        RestAction<Message> action = channel.sendMessage("Calculating Response Time...");
         Consumer<Message> callback = (message) ->  {
            Message m = message; // ^This is a lambda parameter!^
            m.editMessage("Response Time: " + (System.currentTimeMillis() - time) + "ms").queue();
            // End with queue() to not block the callback thread!
          };
         // You can also inline this with the queue parameter: action.queue(m -> m.editMessage(...).queue());
         action.queue(callback);
     

    Example Complete:

    
         MessageChannel channel = event.getChannel();
         final long time = System.currentTimeMillis();
        RestAction<Message> action = channel.sendMessage("Calculating Response Time...");
         Message message = action.complete();
         message.editMessage("Response Time: " + (System.currentTimeMillis() - time) + "ms").queue();
         // End with queue() to not block the callback thread!
     

    Example Planning:

    
         MessageChannel channel = event.getChannel();
        RestAction<Message> action = channel.sendMessage("This message will destroy itself in 5 seconds!");
         action.queue((message) -> message.delete().queueAfter(5, TimeUnit.SECONDS));
     

    Developer Note: It is generally a good practice to use asynchronous logic because blocking threads requires resources which can be avoided by using callbacks over blocking operations:
    queue(Consumer) > complete()

    There is a dedicated wiki page for RestActions that can be useful for learning.

    Since:
    3.0
    • Nested Class Summary

      Nested Classes 
      Modifier and Type Class Description
      static class  RestAction.EmptyRestAction<T>
      Specialized form of RestAction that is used to provide information that has already been retrieved or generated so that another request does not need to be made to Discord.
    • Field Summary

      Fields 
      Modifier and Type Field Description
      static java.util.function.Consumer<java.lang.Throwable> DEFAULT_FAILURE  
      static java.util.function.Consumer DEFAULT_SUCCESS  
      static org.slf4j.Logger LOG  
    • Constructor Summary

      Constructors 
      Constructor Description
      RestAction​(JDA api, net.dv8tion.jda.core.requests.Route.CompiledRoute route)
      Creates a new RestAction instance
      RestAction​(JDA api, net.dv8tion.jda.core.requests.Route.CompiledRoute route, okhttp3.RequestBody data)
      Creates a new RestAction instance
      RestAction​(JDA api, net.dv8tion.jda.core.requests.Route.CompiledRoute route, org.json.JSONObject data)
      Creates a new RestAction instance
    • Method Summary

      All Methods Static Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      T complete()
      Blocks the current Thread and awaits the completion of an submit() request.
      T complete​(boolean shouldQueue)
      Blocks the current Thread and awaits the completion of an submit() request.
      T completeAfter​(long delay, java.util.concurrent.TimeUnit unit)
      Blocks the current Thread for the specified delay and calls complete() when delay has been reached.
      JDA getJDA()
      The current JDA instance
      static boolean isPassContext()
      Whether RestActions will use ContextException automatically to keep track of the caller context.
      void queue()
      Submits a Request for execution.
      void queue​(java.util.function.Consumer<? super T> success)
      Submits a Request for execution.
      void queue​(java.util.function.Consumer<? super T> success, java.util.function.Consumer<? super java.lang.Throwable> failure)
      Submits a Request for execution.
      java.util.concurrent.ScheduledFuture<?> queueAfter​(long delay, java.util.concurrent.TimeUnit unit)
      Schedules a call to queue() to be executed after the specified delay.
      java.util.concurrent.ScheduledFuture<?> queueAfter​(long delay, java.util.concurrent.TimeUnit unit, java.util.concurrent.ScheduledExecutorService executor)
      Schedules a call to queue() to be executed after the specified delay.
      java.util.concurrent.ScheduledFuture<?> queueAfter​(long delay, java.util.concurrent.TimeUnit unit, java.util.function.Consumer<? super T> success)
      Schedules a call to queue(java.util.function.Consumer) to be executed after the specified delay.
      java.util.concurrent.ScheduledFuture<?> queueAfter​(long delay, java.util.concurrent.TimeUnit unit, java.util.function.Consumer<? super T> success, java.util.concurrent.ScheduledExecutorService executor)
      Schedules a call to queue(java.util.function.Consumer) to be executed after the specified delay.
      java.util.concurrent.ScheduledFuture<?> queueAfter​(long delay, java.util.concurrent.TimeUnit unit, java.util.function.Consumer<? super T> success, java.util.function.Consumer<? super java.lang.Throwable> failure)
      Schedules a call to queue(java.util.function.Consumer, java.util.function.Consumer) to be executed after the specified delay.
      java.util.concurrent.ScheduledFuture<?> queueAfter​(long delay, java.util.concurrent.TimeUnit unit, java.util.function.Consumer<? super T> success, java.util.function.Consumer<? super java.lang.Throwable> failure, java.util.concurrent.ScheduledExecutorService executor)
      Schedules a call to queue(java.util.function.Consumer, java.util.function.Consumer) to be executed after the specified delay.
      RestAction<T> setCheck​(java.util.function.BooleanSupplier checks)
      Sets the last-second checks before finally executing the http request in the queue.
      static void setPassContext​(boolean enable)
      If enabled this will pass a ContextException as root-cause to all failure consumers.
      RequestFuture<T> submit()
      Submits a Request for execution and provides a RequestFuture representing its completion task.
      RequestFuture<T> submit​(boolean shouldQueue)
      Submits a Request for execution and provides a RequestFuture representing its completion task.
      java.util.concurrent.ScheduledFuture<T> submitAfter​(long delay, java.util.concurrent.TimeUnit unit)
      Schedules a call to complete() to be executed after the specified delay.
      java.util.concurrent.ScheduledFuture<T> submitAfter​(long delay, java.util.concurrent.TimeUnit unit, java.util.concurrent.ScheduledExecutorService executor)
      Schedules a call to complete() to be executed after the specified delay.
      • Methods inherited from class java.lang.Object

        equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Field Detail

      • LOG

        public static final org.slf4j.Logger LOG
      • DEFAULT_SUCCESS

        public static java.util.function.Consumer DEFAULT_SUCCESS
      • DEFAULT_FAILURE

        public static java.util.function.Consumer<java.lang.Throwable> DEFAULT_FAILURE
    • Constructor Detail

      • RestAction

        public RestAction​(JDA api,
                          net.dv8tion.jda.core.requests.Route.CompiledRoute route)
        Creates a new RestAction instance
        Parameters:
        api - The current JDA instance
        route - The Route.CompiledRoute to be used for rate limit handling
      • RestAction

        public RestAction​(JDA api,
                          net.dv8tion.jda.core.requests.Route.CompiledRoute route,
                          okhttp3.RequestBody data)
        Creates a new RestAction instance
        Parameters:
        api - The current JDA instance
        route - The Route.CompiledRoute to be used for rate limit handling
        data - The data that should be sent to the specified route. (can be null)
      • RestAction

        public RestAction​(JDA api,
                          net.dv8tion.jda.core.requests.Route.CompiledRoute route,
                          org.json.JSONObject data)
        Creates a new RestAction instance
        Parameters:
        api - The current JDA instance
        route - The Route.CompiledRoute to be used for rate limit handling
        data - The data that should be sent to the specified route. (can be null)
    • Method Detail

      • setPassContext

        public static void setPassContext​(boolean enable)
        If enabled this will pass a ContextException as root-cause to all failure consumers. Note that the DEFAULT_FAILURE does not print a stack-trace at all unless specified!
        This might cause performance decrease due to the creation of exceptions for every execution.

        It is recommended to pass a context consumer as failure manually using queue(success, ContextException.here(failure))

        Parameters:
        enable - True, if context should be passed to all failure consumers
      • isPassContext

        public static boolean isPassContext()
        Whether RestActions will use ContextException automatically to keep track of the caller context.
        If set to true this can cause performance drops due to the creation of stack-traces on execution.
        Returns:
        True, if RestActions will keep track of context automatically
        See Also:
        setPassContext(boolean)
      • getJDA

        public JDA getJDA()
        The current JDA instance
        Returns:
        The corresponding JDA instance
      • setCheck

        public RestAction<T> setCheck​(java.util.function.BooleanSupplier checks)
        Sets the last-second checks before finally executing the http request in the queue.
        If the provided supplier evaluates to false or throws an exception this will not be finished. When an exception is thrown from the supplier it will be provided to the failure callback.
        Parameters:
        checks - The checks to run before executing the request, or null to run no checks
        Returns:
        The current RestAction for chaining convenience
      • queue

        public void queue()
        Submits a Request for execution.
        Using the default callback functions: DEFAULT_SUCCESS and DEFAULT_FAILURE

        This method is asynchronous

      • queue

        public void queue​(java.util.function.Consumer<? super T> success)
        Submits a Request for execution.
        Using the default failure callback function.

        This method is asynchronous

        Parameters:
        success - The success callback that will be called at a convenient time for the API. (can be null)
      • queue

        public void queue​(java.util.function.Consumer<? super T> success,
                          java.util.function.Consumer<? super java.lang.Throwable> failure)
        Submits a Request for execution.

        This method is asynchronous

        Parameters:
        success - The success callback that will be called at a convenient time for the API. (can be null)
        failure - The failure callback that will be called if the Request encounters an exception at its execution point.
      • submit

        public RequestFuture<T> submit()
        Submits a Request for execution and provides a RequestFuture representing its completion task.
        Cancelling the returned Future will result in the cancellation of the Request!

        Note: The usage of CompletionStage.toCompletableFuture() is not supported.

        Returns:
        Never-null RequestFuture representing the completion promise
      • submit

        public RequestFuture<T> submit​(boolean shouldQueue)
        Submits a Request for execution and provides a RequestFuture representing its completion task.
        Cancelling the returned Future will result in the cancellation of the Request!

        Note: The usage of CompletionStage.toCompletableFuture() is not supported.

        Parameters:
        shouldQueue - Whether the Request should automatically handle rate limitations. (default true)
        Returns:
        Never-null RequestFuture task representing the completion promise
      • complete

        public T complete()
        Blocks the current Thread and awaits the completion of an submit() request.
        Used for synchronous logic.

        This might throw RuntimeExceptions

        Returns:
        The response value
        Throws:
        java.lang.IllegalStateException - If used within a queue(...) callback
      • complete

        public T complete​(boolean shouldQueue)
                   throws RateLimitedException
        Blocks the current Thread and awaits the completion of an submit() request.
        Used for synchronous logic.
        Parameters:
        shouldQueue - Whether this should automatically handle rate limitations (default true)
        Returns:
        The response value
        Throws:
        java.lang.IllegalStateException - If used within a queue(...) callback
        RateLimitedException - If we were rate limited and the shouldQueue is false. Use complete() to avoid this Exception.
      • submitAfter

        public java.util.concurrent.ScheduledFuture<T> submitAfter​(long delay,
                                                                   java.util.concurrent.TimeUnit unit)
        Schedules a call to complete() to be executed after the specified delay.
        This is an asynchronous operation that will return a ScheduledFuture representing the task.

        The returned Future will provide the return type of a complete() operation when received through the blocking call to Future.get()!

        The global JDA ScheduledExecutorService is used for this operation.
        You can change the core pool size for this Executor through JDABuilder.setCorePoolSize(int) or you can provide your own Executor using submitAfter(long, java.util.concurrent.TimeUnit, java.util.concurrent.ScheduledExecutorService)!

        Parameters:
        delay - The delay after which this computation should be executed, negative to execute immediately
        unit - The TimeUnit to convert the specified delay
        Returns:
        ScheduledFuture representing the delayed operation
        Throws:
        java.lang.IllegalArgumentException - If the provided TimeUnit is null
      • submitAfter

        public java.util.concurrent.ScheduledFuture<T> submitAfter​(long delay,
                                                                   java.util.concurrent.TimeUnit unit,
                                                                   java.util.concurrent.ScheduledExecutorService executor)
        Schedules a call to complete() to be executed after the specified delay.
        This is an asynchronous operation that will return a ScheduledFuture representing the task.

        The returned Future will provide the return type of a complete() operation when received through the blocking call to Future.get()!

        The specified ScheduledExecutorService is used for this operation.

        Parameters:
        delay - The delay after which this computation should be executed, negative to execute immediately
        unit - The TimeUnit to convert the specified delay
        executor - The Non-null ScheduledExecutorService that should be used to schedule this operation
        Returns:
        ScheduledFuture representing the delayed operation
        Throws:
        java.lang.IllegalArgumentException - If the provided TimeUnit or ScheduledExecutorService is null
      • completeAfter

        public T completeAfter​(long delay,
                               java.util.concurrent.TimeUnit unit)
        Blocks the current Thread for the specified delay and calls complete() when delay has been reached.
        If the specified delay is negative this action will execute immediately. (see: TimeUnit.sleep(long))
        Parameters:
        delay - The delay after which to execute a call to complete()
        unit - The TimeUnit which should be used (this will use unit.sleep(delay))
        Returns:
        The response value
        Throws:
        java.lang.IllegalArgumentException - If the specified TimeUnit is null
        java.lang.RuntimeException - If the sleep operation is interrupted
      • queueAfter

        public java.util.concurrent.ScheduledFuture<?> queueAfter​(long delay,
                                                                  java.util.concurrent.TimeUnit unit,
                                                                  java.util.concurrent.ScheduledExecutorService executor)
        Schedules a call to queue() to be executed after the specified delay.
        This is an asynchronous operation that will return a ScheduledFuture representing the task.

        This operation gives no access to the response value.
        Use queueAfter(long, java.util.concurrent.TimeUnit, java.util.function.Consumer) to access the success consumer for queue(java.util.function.Consumer)!

        The specified ScheduledExecutorService is used for this operation.

        Parameters:
        delay - The delay after which this computation should be executed, negative to execute immediately
        unit - The TimeUnit to convert the specified delay
        executor - The Non-null ScheduledExecutorService that should be used to schedule this operation
        Returns:
        ScheduledFuture representing the delayed operation
        Throws:
        java.lang.IllegalArgumentException - If the provided TimeUnit or ScheduledExecutorService is null
      • queueAfter

        public java.util.concurrent.ScheduledFuture<?> queueAfter​(long delay,
                                                                  java.util.concurrent.TimeUnit unit,
                                                                  java.util.function.Consumer<? super T> success,
                                                                  java.util.concurrent.ScheduledExecutorService executor)
        Schedules a call to queue(java.util.function.Consumer) to be executed after the specified delay.
        This is an asynchronous operation that will return a ScheduledFuture representing the task.

        This operation gives no access to the failure callback.
        Use queueAfter(long, java.util.concurrent.TimeUnit, java.util.function.Consumer, java.util.function.Consumer) to access the failure consumer for queue(java.util.function.Consumer, java.util.function.Consumer)!

        The specified ScheduledExecutorService is used for this operation.

        Parameters:
        delay - The delay after which this computation should be executed, negative to execute immediately
        unit - The TimeUnit to convert the specified delay
        success - The success Consumer that should be called once the queue(java.util.function.Consumer) operation completes successfully.
        executor - The Non-null ScheduledExecutorService that should be used to schedule this operation
        Returns:
        ScheduledFuture representing the delayed operation
        Throws:
        java.lang.IllegalArgumentException - If the provided TimeUnit or ScheduledExecutorService is null
      • queueAfter

        public java.util.concurrent.ScheduledFuture<?> queueAfter​(long delay,
                                                                  java.util.concurrent.TimeUnit unit,
                                                                  java.util.function.Consumer<? super T> success,
                                                                  java.util.function.Consumer<? super java.lang.Throwable> failure,
                                                                  java.util.concurrent.ScheduledExecutorService executor)
        Schedules a call to queue(java.util.function.Consumer, java.util.function.Consumer) to be executed after the specified delay.
        This is an asynchronous operation that will return a ScheduledFuture representing the task.

        The specified ScheduledExecutorService is used for this operation.

        Parameters:
        delay - The delay after which this computation should be executed, negative to execute immediately
        unit - The TimeUnit to convert the specified delay
        success - The success Consumer that should be called once the queue(java.util.function.Consumer, java.util.function.Consumer) operation completes successfully.
        failure - The failure Consumer that should be called in case of an error of the queue(java.util.function.Consumer, java.util.function.Consumer) operation.
        executor - The Non-null ScheduledExecutorService that should be used to schedule this operation
        Returns:
        ScheduledFuture representing the delayed operation
        Throws:
        java.lang.IllegalArgumentException - If the provided TimeUnit or ScheduledExecutorService is null