Interface PaginationAction<T,M extends PaginationAction<T,M>>

Type Parameters:
M - The current implementation used as chaining return value
T - The type of entity to paginate
All Superinterfaces:
Iterable<T>, RestAction<List<T>>
All Known Subinterfaces:
AuditLogPaginationAction, BanPaginationAction, EntitlementPaginationAction, MessagePaginationAction, ReactionPaginationAction, ScheduledEventMembersPaginationAction, ThreadChannelPaginationAction, ThreadMemberPaginationAction

public interface PaginationAction<T,M extends PaginationAction<T,M>> extends RestAction<List<T>>, Iterable<T>
RestAction specification used to retrieve entities for paginated endpoints (before, after, limit).
Note that this implementation is not considered thread-safe as modifications to the cache are not done with a lock. Calling methods on this class from multiple threads is not recommended.

Examples


 /**
   * Retrieves messages until the specified limit is reached. The messages will be limited after being filtered by the user.
   * If the user hasn't sent enough messages this will go through all messages so it is recommended to add an additional end condition.
   */
 public static List<Message> getMessagesByUser(MessageChannel channel, User user, int limit)
 {
     MessagePaginationAction action = channel.getIterableHistory();
     Stream<Message> messageStream = action.stream()
             .limit(limit * 2) // used to limit amount of messages to check, if user hasn't sent enough messages it would go on forever
             .filter( message-> message.getAuthor().equals(user) )
             .limit(limit); // limit on filtered stream will be checked independently from previous limit
     return messageStream.collect(Collectors.toList());
 }
 

 /**
  * Iterates messages in an async stream and stops once the limit has been reached.
  */
 public static void onEachMessageAsync(MessageChannel channel, Consumer<Message> consumer, int limit)
 {
     if (limit< 1)
         return;
     MessagePaginationAction action = channel.getIterableHistory();
     AtomicInteger counter = new AtomicInteger(limit);
     action.forEachAsync( (message)->
     {
         consumer.accept(message);
         // if false the iteration is terminated; else it continues
         return counter.decrementAndGet() == 0;
     });
 }
 
Since:
3.1
  • Method Details

    • skipTo

      @Nonnull M skipTo(long id)
      Skips past the specified ID for successive requests. This will reset the getLast() entity and cause a NoSuchElementException to be thrown when attempting to get the last entity until a new retrieve action has been done.
      If cache is disabled this can be set to an arbitrary value irrelevant of the current last. Set this to 0 to start from the most recent message.

      Fails if cache is enabled and the target id is newer than the current last id (id > last).

      Example

      
       public MessagePaginationAction getOlderThan(MessageChannel channel, long time) {
           final long timestamp = TimeUtil.getDiscordTimestamp(time);
           final MessagePaginationAction paginator = channel.getIterableHistory();
           return paginator.skipTo(timestamp);
       }
      
       getOlderThan(channel, System.currentTimeMillis() - TimeUnit.DAYS.toMillis(14))
           .forEachAsync((message) -> {
               boolean empty = message.getContentRaw().isEmpty();
               if (!empty)
                   System.out.printf("%#s%n", message); // means: print display content
               return !empty; // means: continue if not empty
           });
       
      Parameters:
      id - The snowflake ID to skip before, this is exclusive rather than inclusive
      Returns:
      The current PaginationAction for chaining convenience
      Throws:
      IllegalArgumentException - If cache is enabled, and you are attempting to skip forward in time (id > last)
      See Also:
    • getLastKey

      long getLastKey()
      The current iteration anchor used for pagination.
      This is updated by each retrieve action.
      Returns:
      The current iteration anchor
      See Also:
    • setCheck

      @Nonnull M setCheck(@Nullable BooleanSupplier checks)
      Description copied from interface: RestAction
      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.
      Specified by:
      setCheck in interface RestAction<T>
      Parameters:
      checks - The checks to run before executing the request, or null to run no checks
      Returns:
      The current RestAction for chaining convenience
      See Also:
    • timeout

      @Nonnull M timeout(long timeout, @Nonnull TimeUnit unit)
      Description copied from interface: RestAction
      Timeout for this RestAction instance.
      If the request doesn't get executed within the timeout it will fail.

      When a RestAction times out, it will fail with a TimeoutException. This is the same as deadline(System.currentTimeMillis() + unit.toMillis(timeout)).

      Example

      
       action.timeout(10, TimeUnit.SECONDS) // 10 seconds from now
             .queueAfter(20, SECONDS); // request will not be executed within deadline and timeout immediately after 20 seconds
       
      Specified by:
      timeout in interface RestAction<T>
      Parameters:
      timeout - The timeout to use
      unit - Unit for the timeout value
      Returns:
      The same RestAction instance with the applied timeout
      See Also:
    • deadline

      @Nonnull M deadline(long timestamp)
      Description copied from interface: RestAction
      Similar to RestAction.timeout(long, TimeUnit) but schedules a deadline at which the request has to be completed.
      If the deadline is reached, the request will fail with a TimeoutException.

      This does not mean that the request will immediately timeout when the deadline is reached. JDA will check the deadline right before executing the request or within intervals in a worker thread. This only means the request will timeout if the deadline has passed.

      Example

      
       action.deadline(System.currentTimeMillis() + 10000) // 10 seconds from now
             .queueAfter(20, SECONDS); // request will not be executed within deadline and timeout immediately after 20 seconds
       
      Specified by:
      deadline in interface RestAction<T>
      Parameters:
      timestamp - Millisecond timestamp at which the request will timeout
      Returns:
      The same RestAction with the applied deadline
      See Also:
    • getSupportedOrders

      @Nonnull default EnumSet<PaginationAction.PaginationOrder> getSupportedOrders()
      The supported PaginationOrders for this pagination action.
      All enum values that are not returned will cause a throw for order(PaginationOrder).

      Most pagination endpoints only support a single order, however some endpoints such as message pagination supports both.

      Returns:
      EnumSet of PaginationAction.PaginationOrder (Modifying this set does not affect this class)
    • getOrder

      The current iteration order.
      This defaults to PaginationAction.PaginationOrder.BACKWARD, meaning most recent first, for most pagination endpoints.
      Returns:
      The PaginationAction.PaginationOrder
      See Also:
    • order

      Configure the PaginationAction.PaginationOrder of this pagination action.

      You can only supply supported orders, see getSupportedOrders().

      Parameters:
      order - The pagination order
      Returns:
      The current PaginationAction implementation instance
      Throws:
      IllegalArgumentException - If the provided pagination order is null or unsupported
      IllegalStateException - If this pagination action has already been used to retrieve entities
      See Also:
    • reverse

      @Nonnull default M reverse()
      Flips the order(PaginationOrder) of this pagination action.
      Returns:
      The current PaginationAction implementation instance
      Throws:
      IllegalArgumentException - If this pagination action does not support the reversed order
    • cacheSize

      int cacheSize()
      The current amount of cached entities for this PaginationAction
      Returns:
      int size of currently cached entities
    • isEmpty

      boolean isEmpty()
      Whether the cache of this PaginationAction is empty.
      Logically equivalent to cacheSize() == 0.
      Returns:
      True, if no entities have been retrieved yet.
    • getCached

      @Nonnull List<T> getCached()
      The currently cached entities of recent execution tasks.
      Every RestAction success adds to this List. (Thread-Safe due to CopyOnWriteArrayList)

      This does not contain all entities for the paginated endpoint unless the pagination has reached an end!
      It only contains those entities which already have been retrieved.

      Returns:
      Immutable List containing all currently cached entities for this PaginationAction
    • getLast

      @Nonnull T getLast()
      The most recent entity retrieved by this PaginationAction instance
      Returns:
      The most recent cached entity
      Throws:
      NoSuchElementException - If no entities have been retrieved yet (see isEmpty())
    • getFirst

      @Nonnull T getFirst()
      The first cached entity retrieved by this PaginationAction instance
      Returns:
      The very first cached entity
      Throws:
      NoSuchElementException - If no entities have been retrieved yet (see isEmpty())
    • limit

      @Nonnull M limit(int limit)
      Sets the limit that should be used in the next RestAction completion call.

      The specified limit may not be below the Minimum Limit nor above the Maximum Limit. Unless these limits are specifically omitted. (See documentation of methods)

      This limit represents how many entities will be retrieved per request and NOT the maximum amount of entities that should be retrieved for iteration/sequencing.
      action.limit(50).complete()
      is not the same as
      action.stream().limit(50).collect(collector)

      Parameters:
      limit - The limit to use
      Returns:
      The current PaginationAction implementation instance
      Throws:
      IllegalArgumentException - If the provided limit is out of range
    • cache

      @Nonnull M cache(boolean enableCache)
      Whether already retrieved entities should be stored within the internal cache. All cached entities will be available from getCached(). Default: true
      This being disabled allows unused entities to be removed from the memory heap by the garbage collector. If this is enabled this will not take place until all references to this PaginationAction have been cleared.
      Parameters:
      enableCache - Whether to enable entity cache
      Returns:
      The current PaginationAction implementation instance
    • isCacheEnabled

      boolean isCacheEnabled()
      Whether retrieved entities are stored within an internal cache. If this is false entities retrieved by the iterator or a call to a RestAction terminal operation will not be retrievable from getCached().
      This being disabled allows unused entities to be removed from the memory heap by the garbage collector. If this is enabled this will not take place until all references to this PaginationAction have been cleared.
      Returns:
      True, If entities will be cached.
    • getMaxLimit

      int getMaxLimit()
      The maximum limit that can be used for this PaginationAction
      Limits provided to limit(int) must not be greater than the returned value.
      If no maximum limit is used this will return 0. That means there is no upper border for limiting this PaginationAction
      Returns:
      The maximum limit
    • getMinLimit

      int getMinLimit()
      The minimum limit that can be used for this PaginationAction
      Limits provided to limit(int) must not be less than the returned value.
      If no minimum limit is used this will return 0. That means there is no lower border for limiting this PaginationAction
      Returns:
      The minimum limit
    • getLimit

      int getLimit()
      The currently used limit.
      If this PaginationAction does not use limitation this will return 0
      Returns:
      limit
    • takeWhileAsync

      @Nonnull default CompletableFuture<List<T>> takeWhileAsync(@Nonnull Predicate<? super T> rule)
      Retrieves elements while the specified condition is met.
      Parameters:
      rule - The rule which must be fulfilled for an element to be added, returns false to discard the element and finish the task
      Returns:
      CompletableFuture - Type: List
      Future representing the fetch task, the list will be sorted most recent to oldest
      Throws:
      IllegalArgumentException - If the provided rule is null
      See Also:
    • takeWhileAsync

      @Nonnull default CompletableFuture<List<T>> takeWhileAsync(int limit, @Nonnull Predicate<? super T> rule)
      Retrieves elements while the specified condition is met.
      Parameters:
      limit - The maximum amount of elements to collect or 0 for no limit
      rule - The rule which must be fulfilled for an element to be added, returns false to discard the element and finish the task
      Returns:
      CompletableFuture - Type: List
      Future representing the fetch task, the list will be sorted most recent to oldest
      Throws:
      IllegalArgumentException - If the provided rule is null or the limit is negative
      See Also:
    • takeUntilAsync

      @Nonnull default CompletableFuture<List<T>> takeUntilAsync(@Nonnull Predicate<? super T> rule)
      Retrieves elements until the specified condition is met.
      Parameters:
      rule - The rule which must be fulfilled for an element to be discarded, returns true to discard the element and finish the task
      Returns:
      CompletableFuture - Type: List
      Future representing the fetch task, the list will be sorted most recent to oldest
      Throws:
      IllegalArgumentException - If the provided rule is null
      See Also:
    • takeUntilAsync

      @Nonnull default CompletableFuture<List<T>> takeUntilAsync(int limit, @Nonnull Predicate<? super T> rule)
      Retrieves elements until the specified condition is met.
      Parameters:
      limit - The maximum amount of elements to collect or 0 for no limit
      rule - The rule which must be fulfilled for an element to be discarded, returns true to discard the element and finish the task
      Returns:
      CompletableFuture - Type: List
      Future representing the fetch task, the list will be sorted most recent to oldest
      Throws:
      IllegalArgumentException - If the provided rule is null or the limit is negative
      See Also:
    • takeAsync

      @Nonnull CompletableFuture<List<T>> takeAsync(int amount)
      Convenience method to retrieve an amount of entities from this pagination action.
      This also includes already cached entities similar to forEachAsync(Procedure).
      Parameters:
      amount - The maximum amount to retrieve
      Returns:
      CompletableFuture - Type: List
      See Also:
    • takeRemainingAsync

      @Nonnull CompletableFuture<List<T>> takeRemainingAsync(int amount)
      Convenience method to retrieve an amount of entities from this pagination action.
      Unlike takeAsync(int) this does not include already cached entities.
      Parameters:
      amount - The maximum amount to retrieve
      Returns:
      CompletableFuture - Type: List
      See Also:
    • forEachAsync

      @Nonnull default CompletableFuture<?> forEachAsync(@Nonnull Procedure<? super T> action)
      Iterates over all entities until the provided action returns false!
      This operation is different from Iterable.forEach(Consumer) as it uses successive RestAction.queue() tasks to iterate each entity in callback threads instead of the calling active thread. This means that this method fully works on different threads to retrieve new entities.

      This iteration will include already cached entities, in order to exclude cached entities use forEachRemainingAsync(Procedure)

      Example

      
       //deletes messages until it finds a user that is still in guild
       public void cleanupMessages(MessagePaginationAction action)
       {
           action.forEachAsync( (message) ->
           {
               Guild guild = message.getGuild();
               if (!guild.isMember(message.getAuthor()))
                   message.delete().queue();
               else
                   return false;
               return true;
           });
       }
       
      Parameters:
      action - Procedure returning true if iteration should continue!
      Returns:
      Future that can be cancelled to stop iteration from outside!
      Throws:
      IllegalArgumentException - If the provided Procedure is null
    • forEachAsync

      @Nonnull CompletableFuture<?> forEachAsync(@Nonnull Procedure<? super T> action, @Nonnull Consumer<? super Throwable> failure)
      Iterates over all entities until the provided action returns false!
      This operation is different from Iterable.forEach(Consumer) as it uses successive RestAction.queue() tasks to iterate each entity in callback threads instead of the calling active thread. This means that this method fully works on different threads to retrieve new entities.

      This iteration will include already cached entities, in order to exclude cached entities use forEachRemainingAsync(Procedure, Consumer)

      Example

      
       //deletes messages until it finds a user that is still in guild
       public void cleanupMessages(MessagePaginationAction action)
       {
           action.forEachAsync( (message) ->
           {
               Guild guild = message.getGuild();
               if (!guild.isMember(message.getAuthor()))
                   message.delete().queue();
               else
                   return false;
               return true;
           }, Throwable::printStackTrace);
       }
       
      Parameters:
      action - Procedure returning true if iteration should continue!
      failure - Consumer that should handle any throwables from the action
      Returns:
      Future that can be cancelled to stop iteration from outside!
      Throws:
      IllegalArgumentException - If the provided Procedure or the failure Consumer is null
    • forEachRemainingAsync

      @Nonnull default CompletableFuture<?> forEachRemainingAsync(@Nonnull Procedure<? super T> action)
      Iterates over all remaining entities until the provided action returns false!
      This operation is different from forEachRemaining(Procedure) as it uses successive RestAction.queue() tasks to iterate each entity in callback threads instead of the calling active thread. This means that this method fully works on different threads to retrieve new entities.

      This iteration will exclude already cached entities, in order to include cached entities use forEachAsync(Procedure)

      Example

      
       //deletes messages until it finds a user that is still in guild
       public void cleanupMessages(MessagePaginationAction action)
       {
           action.forEachRemainingAsync( (message) ->
           {
               Guild guild = message.getGuild();
               if (!guild.isMember(message.getAuthor()))
                   message.delete().queue();
               else
                   return false;
               return true;
           });
       }
       
      Parameters:
      action - Procedure returning true if iteration should continue!
      Returns:
      Future that can be cancelled to stop iteration from outside!
      Throws:
      IllegalArgumentException - If the provided Procedure is null
    • forEachRemainingAsync

      @Nonnull CompletableFuture<?> forEachRemainingAsync(@Nonnull Procedure<? super T> action, @Nonnull Consumer<? super Throwable> failure)
      Iterates over all remaining entities until the provided action returns false!
      This operation is different from forEachRemaining(Procedure) as it uses successive RestAction.queue() tasks to iterate each entity in callback threads instead of the calling active thread. This means that this method fully works on different threads to retrieve new entities.

      This iteration will exclude already cached entities, in order to include cached entities use forEachAsync(Procedure, Consumer)

      Example

      
       //deletes messages until it finds a user that is still in guild
       public void cleanupMessages(MessagePaginationAction action)
       {
           action.forEachRemainingAsync( (message) ->
           {
               Guild guild = message.getGuild();
               if (!guild.isMember(message.getAuthor()))
                   message.delete().queue();
               else
                   return false;
               return true;
           }, Throwable::printStackTrace);
       }
       
      Parameters:
      action - Procedure returning true if iteration should continue!
      failure - Consumer that should handle any throwables from the action
      Returns:
      Future that can be cancelled to stop iteration from outside!
      Throws:
      IllegalArgumentException - If the provided Procedure or the failure Consumer is null
    • forEachRemaining

      void forEachRemaining(@Nonnull Procedure<? super T> action)
      Iterates over all remaining entities until the provided action returns false!
      Skipping past already cached entities to iterate all remaining entities of this PaginationAction.

      This is a blocking operation that might take a while to complete

      Parameters:
      action - The Procedure which should return true to continue iterating
    • spliterator

      default Spliterator<T> spliterator()
      Specified by:
      spliterator in interface Iterable<T>
    • stream

      @Nonnull default Stream<T> stream()
      A sequential Stream with this PaginationAction as its source.
      Returns:
      a sequential Stream over the elements in this PaginationAction
    • parallelStream

      @Nonnull default Stream<T> parallelStream()
      Returns a possibly parallel Stream with this PaginationAction as its source. It is allowable for this method to return a sequential stream.
      Returns:
      a sequential Stream over the elements in this PaginationAction
    • iterator

      PaginationIterator that will iterate over all entities for this PaginationAction.
      Specified by:
      iterator in interface Iterable<T>
      Returns:
      new PaginationIterator