View Javadoc

1   package com.atlassian.marketplace.client.api;
2   
3   import java.util.Iterator;
4   
5   import com.atlassian.fugue.Option;
6   
7   import com.google.common.collect.ImmutableList;
8   import com.google.common.collect.Iterables;
9   
10  import static com.atlassian.fugue.Option.none;
11  import static com.google.common.base.Preconditions.checkNotNull;
12  import static com.google.common.collect.Iterables.isEmpty;
13  
14  /**
15   * A subset of items returned by a query. The maximum size of the subset is determined by the
16   * <tt>limit</tt> parameter used in the query, or by the server's maximum result set size,
17   * whichever is lower.
18   * <p>
19   * The items themselves are accessed by treating the page as an Iterable.
20   * <p>
21   * To get the next or previous page of query results, if any, pass a {@link PageReference}
22   * obtained from {@link #getNext()} or {@link #getPrevious()} to the client's generic
23   * {@link com.atlassian.marketplace.client.MarketplaceClient#getMore} method.
24   * for the type of items.  For instance, for plugin listings:
25   * <pre>
26   *     Page&lt;AddonSummary&gt; aPage = client.addons().find(addonQuery);
27   *     if (aPage.getNext().isDefined())
28   *     {
29   *         for (PageReference&lt;AddonSummary&gt; next: aPage.getNext())
30   *         {
31   *             Page&lt;AddonSummary&gt; nextPage = client.getMore(next);
32   *         }
33   *     }
34   * </pre>
35   */
36  public abstract class Page<T> implements Iterable<T>
37  {
38      private final ImmutableList<T> items;
39      private final int totalSize;
40      protected final PageReader<T> reader;
41  
42      /**
43       * Returns a Page containing no items, with no server URI ({@link #getReference()}, {@link #getNext()},
44       * and {@link #getPrevious()} will all return {@link Option#none()}).
45       */
46      @SuppressWarnings("unchecked")
47      public static <T> Page<T> empty()
48      {
49          return (Page<T>) EMPTY_PAGE;
50      }
51  
52      /**
53       * Returns a Page containing no items, with no server URI ({@link #getReference()}, {@link #getNext()},
54       * and {@link #getPrevious()} will all return {@link Option#none()}).
55       */
56      @SuppressWarnings("unchecked")
57      public static <T> Page<T> empty(final Class<T> type)
58      {
59          return (Page<T>) EMPTY_PAGE;
60      }
61  
62      /**
63       * Returns a Page from a fixed list of items, with no server URI ({@link #getReference()},
64       * {@link #getNext()}, and {@link #getPrevious()} will all return {@link Option#none()}).
65       */
66      public static <T> Page<T> fromItems(Iterable<T> items)
67      {
68          return isEmpty(items) ? Page.<T>empty() : new FixedPage<T>(items);
69      }
70      
71      protected Page(Iterable<T> items, int totalSize, PageReader<T> reader)
72      {
73          this.items = ImmutableList.copyOf(checkNotNull(items, "items"));
74          this.totalSize = totalSize;
75          this.reader = checkNotNull(reader);
76      }
77      
78      @Override
79      public Iterator<T> iterator()
80      {
81          return items.iterator();
82      }
83      
84      /**
85       * The number of items on this page.
86       */
87      public int size()
88      {
89          return items.size();
90      }
91      
92      /**
93       * The number of items in the entire result set, of which this page is a subset.
94       */
95      public int totalSize()
96      {
97          return totalSize;
98      }
99      
100     /**
101      * Returns a reference to the address of this query page on the server allowing it to be requeried
102      * in the future, or {@link Option#none()} if it does not exist on the server.
103      */
104     public abstract Option<PageReference<T>> getReference();
105     
106     /**
107      * If there are other items before this subset in the full result set, returns a {@link PageReference}
108      * allowing you to query the previous page; otherwise returns {@link Option#none()}.
109      */
110     public abstract Option<PageReference<T>> getPrevious();
111     
112     /**
113      * If there are other items after this subset in the full result set, returns a {@link PageReference}
114      * allowing you to query the next page; otherwise returns {@link Option#none()}.
115      */
116     public abstract Option<PageReference<T>> getNext();
117 
118     /**
119      * Shortcut for <tt>getReference().get().getOffset()</tt>, but returns zero if <tt>getReference()</tt>
120      * is <tt>none()</tt>.
121      */
122     public int getOffset()
123     {
124         for (PageReference<T> ref: getReference())
125         {
126             return ref.getBounds().getOffset();
127         }
128         return 0;
129     }
130     
131     private static final Page<Object> EMPTY_PAGE = new FixedPage<Object>(ImmutableList.<Object>of());
132     
133     private static final class FixedPage<T> extends Page<T>
134     {
135         FixedPage(Iterable<T> items)
136         {
137             super(ImmutableList.copyOf(items), Iterables.size(items), PageReader.<T>stub());
138         }
139         
140         @Override
141         public Option<PageReference<T>> getReference()
142         {
143             return none();
144         }
145         
146         @Override
147         public Option<PageReference<T>> getPrevious()
148         {
149             return none();
150         }
151         
152         @Override
153         public Option<PageReference<T>> getNext()
154         {
155             return none();
156         }
157     };
158 }