1 /* 2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"). 5 * You may not use this file except in compliance with the License. 6 * A copy of the License is located at 7 * 8 * http://aws.amazon.com/apache2.0 9 * 10 * or in the "license" file accompanying this file. This file is distributed 11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 * express or implied. See the License for the specific language governing 13 * permissions and limitations under the License. 14 */ 15 16 package software.amazon.awssdk.core.pagination.sync; 17 18 import java.util.Collections; 19 import java.util.Iterator; 20 import java.util.NoSuchElementException; 21 import java.util.function.Function; 22 import software.amazon.awssdk.annotations.SdkProtectedApi; 23 24 /** 25 * Iterable for the paginated items. This class can be used through iterate through 26 * all the items across multiple pages until there is no more response from the service. 27 * 28 * @param <ResponseT> The type of a single response page 29 * @param <ItemT> The type of paginated member in a response page 30 */ 31 @SdkProtectedApi 32 public final class PaginatedItemsIterable<ResponseT, ItemT> implements SdkIterable<ItemT> { 33 34 private final SdkIterable<ResponseT> pagesIterable; 35 private final Function<ResponseT, Iterator<ItemT>> getItemIterator; 36 PaginatedItemsIterable(BuilderImpl<ResponseT, ItemT> builder)37 private PaginatedItemsIterable(BuilderImpl<ResponseT, ItemT> builder) { 38 this.pagesIterable = builder.pagesIterable; 39 this.getItemIterator = builder.itemIteratorFunction; 40 } 41 builder()42 public static <R, T> Builder<R, T> builder() { 43 return new BuilderImpl<>(); 44 } 45 46 @Override iterator()47 public Iterator<ItemT> iterator() { 48 return new ItemsIterator(pagesIterable.iterator()); 49 } 50 51 private class ItemsIterator implements Iterator<ItemT> { 52 53 private final Iterator<ResponseT> pagesIterator; 54 private Iterator<ItemT> singlePageItemsIterator; 55 ItemsIterator(final Iterator<ResponseT> pagesIterator)56 ItemsIterator(final Iterator<ResponseT> pagesIterator) { 57 this.pagesIterator = pagesIterator; 58 this.singlePageItemsIterator = pagesIterator.hasNext() ? getItemIterator.apply(pagesIterator.next()) 59 : Collections.emptyIterator(); 60 } 61 62 @Override hasNext()63 public boolean hasNext() { 64 while (!hasMoreItems() && pagesIterator.hasNext()) { 65 singlePageItemsIterator = getItemIterator.apply(pagesIterator.next()); 66 } 67 68 if (hasMoreItems()) { 69 return true; 70 } 71 72 return false; 73 } 74 75 @Override next()76 public ItemT next() { 77 if (!hasNext()) { 78 throw new NoSuchElementException("No more elements left"); 79 } 80 81 return singlePageItemsIterator.next(); 82 } 83 hasMoreItems()84 private boolean hasMoreItems() { 85 return singlePageItemsIterator.hasNext(); 86 } 87 } 88 89 public interface Builder<ResponseT, ItemT> { pagesIterable(SdkIterable<ResponseT> sdkIterable)90 Builder<ResponseT, ItemT> pagesIterable(SdkIterable<ResponseT> sdkIterable); 91 itemIteratorFunction(Function<ResponseT, Iterator<ItemT>> itemIteratorFunction)92 Builder<ResponseT, ItemT> itemIteratorFunction(Function<ResponseT, Iterator<ItemT>> itemIteratorFunction); 93 build()94 PaginatedItemsIterable<ResponseT, ItemT> build(); 95 } 96 97 private static final class BuilderImpl<ResponseT, ItemT> implements Builder<ResponseT, ItemT> { 98 private SdkIterable<ResponseT> pagesIterable; 99 private Function<ResponseT, Iterator<ItemT>> itemIteratorFunction; 100 BuilderImpl()101 private BuilderImpl() { 102 } 103 104 @Override pagesIterable(SdkIterable<ResponseT> pagesIterable)105 public Builder<ResponseT, ItemT> pagesIterable(SdkIterable<ResponseT> pagesIterable) { 106 this.pagesIterable = pagesIterable; 107 return this; 108 } 109 110 @Override itemIteratorFunction(Function<ResponseT, Iterator<ItemT>> itemIteratorFunction)111 public Builder<ResponseT, ItemT> itemIteratorFunction(Function<ResponseT, Iterator<ItemT>> itemIteratorFunction) { 112 this.itemIteratorFunction = itemIteratorFunction; 113 return this; 114 } 115 116 @Override build()117 public PaginatedItemsIterable<ResponseT, ItemT> build() { 118 return new PaginatedItemsIterable<>(this); 119 } 120 } 121 } 122