1 package com.atlassian.user.search.page;
2
3 import com.atlassian.user.EntityException;
4 import org.apache.log4j.Category;
5
6 import java.util.*;
7
8 public abstract class AbstractPrefetchingPager<T> implements Pager<T>, Iterator<T>
9 {
10 public static final Category log = Category.getInstance(AbstractPrefetchingPager.class);
11 protected int idx = 0;
12 private final int preloadLimit = PRELOAD_LIMIT;
13 private final List<T> prefetched = new ArrayList<T>(preloadLimit);
14 protected int indexOfFirstItemInCurrentPage = 0;
15 public boolean lastPage;
16
17 public Iterator<T> iterator()
18 {
19 return this;
20 }
21
22 public boolean isEmpty()
23 {
24 return !hasNext();
25 }
26
27 public List<T> getCurrentPage()
28 {
29 return new ArrayList<T>(prefetched);
30 }
31
32 public boolean hasNext()
33 {
34 int indexWithinPage = getIndexWithinPage();
35 if (indexWithinPage == prefetched.size() && !lastPage)
36 {
37 preload();
38 indexWithinPage = getIndexWithinPage();
39 }
40 return indexWithinPage < prefetched.size() || !lastPage;
41 }
42
43 protected abstract void preload();
44
45 public void remove()
46 {
47 throw new UnsupportedOperationException();
48 }
49
50 protected void preload(Iterator iterator)
51 {
52 prefetched.clear();
53 int currentPos = 0;
54
55 try
56 {
57 while (!lastPage && prefetched.size() < preloadLimit)
58 {
59 if (!iterator.hasNext())
60 {
61 lastPage = true;
62 break;
63 }
64
65 Object element = iterator.next();
66
67 List<T> entities = new ArrayList<T>();
68 fetch(element, entities);
69
70 for (Iterator<T> i = entities.iterator(); i.hasNext() && prefetched.size() < preloadLimit;)
71 {
72 T r = i.next();
73 if (currentPos >= idx)
74 {
75 prefetched.add(r);
76 }
77 ++currentPos;
78 }
79 }
80 if (prefetched.size() < preloadLimit)
81 {
82 lastPage = true;
83 }
84 }
85 catch (Exception e)
86 {
87 log.error("At index [" + idx + "]: " + e.getMessage(), e);
88 lastPage = true;
89 }
90 }
91
92 abstract protected List<T> fetch(Object element, List<T> prefetched) throws EntityException;
93
94 public void nextPage()
95 {
96 idx += PRELOAD_LIMIT;
97 preload();
98 }
99
100 public int getIndex()
101 {
102 return idx;
103 }
104
105 public void skipTo(int idx) throws PagerException
106 {
107 this.idx = idx;
108 preload();
109
110 if (prefetched == null || prefetched.size() == 0)
111 {
112 this.idx = NO_POSITION;
113 }
114 }
115
116 public boolean onLastPage()
117 {
118 return lastPage;
119 }
120
121 public int getIndexOfFirstItemInCurrentPage()
122 {
123 return indexOfFirstItemInCurrentPage;
124 }
125
126 public T next()
127 {
128 if (!hasNext())
129 throw new NoSuchElementException();
130 int indexWithinPage = getIndexWithinPage();
131 T nextObj = prefetched.get(indexWithinPage);
132 idx++;
133
134 return nextObj;
135 }
136
137 protected int getIndexWithinPage()
138 {
139 return idx - indexOfFirstItemInCurrentPage;
140 }
141 }