1 | package org.springframework.batch.item.data; |
2 | |
3 | import java.util.Iterator; |
4 | |
5 | import org.springframework.batch.item.ItemReader; |
6 | import org.springframework.batch.item.ItemStreamReader; |
7 | import org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader; |
8 | |
9 | /** |
10 | * A base class that handles basic reading logic based on the paginated |
11 | * semantics of Spring Data's paginated facilities. It also handles the |
12 | * semantics required for restartability based on those facilities. |
13 | * |
14 | * @author Michael Minella |
15 | * @since 2.2 |
16 | * @param <T> Type of item to be read |
17 | */ |
18 | public abstract class AbstractPaginatedDataItemReader<T> extends |
19 | AbstractItemCountingItemStreamItemReader<T> { |
20 | |
21 | protected volatile int page = 0; |
22 | |
23 | protected int pageSize = 10; |
24 | |
25 | protected Iterator<T> results; |
26 | |
27 | private Object lock = new Object(); |
28 | |
29 | /** |
30 | * The number of items to be read with each page. |
31 | * |
32 | * @param pageSize the number of items |
33 | */ |
34 | public void setPageSize(int pageSize) { |
35 | this.pageSize = pageSize; |
36 | } |
37 | |
38 | @Override |
39 | protected T doRead() throws Exception { |
40 | |
41 | synchronized (lock) { |
42 | if(results == null || !results.hasNext()) { |
43 | |
44 | results = doPageRead(); |
45 | |
46 | page ++; |
47 | |
48 | if(results == null || !results.hasNext()) { |
49 | return null; |
50 | } |
51 | } |
52 | |
53 | |
54 | if(results.hasNext()) { |
55 | return results.next(); |
56 | } |
57 | else { |
58 | return null; |
59 | } |
60 | } |
61 | } |
62 | |
63 | /** |
64 | * Method this {@link ItemStreamReader} delegates to |
65 | * for the actual work of reading a page. Each time |
66 | * this method is called, the resulting {@link Iterator} |
67 | * should contain the items read within the next page. |
68 | * <br/><br/> |
69 | * If the {@link Iterator} is empty or null when it is |
70 | * returned, this {@link ItemReader} will assume that the |
71 | * input has been exhausted. |
72 | * |
73 | * @return an {@link Iterator} containing the items within a page. |
74 | */ |
75 | protected abstract Iterator<T> doPageRead(); |
76 | |
77 | @Override |
78 | protected void doOpen() throws Exception { |
79 | } |
80 | |
81 | @Override |
82 | protected void doClose() throws Exception { |
83 | } |
84 | |
85 | @Override |
86 | protected void jumpToItem(int itemLastIndex) throws Exception { |
87 | synchronized (lock) { |
88 | page = itemLastIndex / pageSize; |
89 | int current = itemLastIndex % pageSize; |
90 | |
91 | Iterator<T> initialPage = doPageRead(); |
92 | |
93 | for(; current >= 0; current--) { |
94 | initialPage.next(); |
95 | } |
96 | } |
97 | } |
98 | } |