|
20 | 20 | package it.bancaditalia.oss.vtl.util;
|
21 | 21 |
|
22 | 22 | import static java.time.temporal.ChronoUnit.DAYS;
|
23 |
| -import static java.util.concurrent.TimeUnit.SECONDS; |
24 | 23 |
|
25 | 24 | import java.io.Serializable;
|
26 | 25 | import java.time.LocalDate;
|
27 | 26 | import java.util.ArrayList;
|
28 |
| -import java.util.HashMap; |
29 |
| -import java.util.List; |
30 |
| -import java.util.Map; |
31 |
| -import java.util.concurrent.ArrayBlockingQueue; |
32 |
| -import java.util.concurrent.BlockingQueue; |
| 27 | +import java.util.Iterator; |
33 | 28 | import java.util.stream.Stream;
|
34 | 29 |
|
35 | 30 | import org.slf4j.Logger;
|
|
43 | 38 | import it.bancaditalia.oss.vtl.model.domain.DateDomain;
|
44 | 39 | import it.bancaditalia.oss.vtl.model.domain.NumberDomain;
|
45 | 40 |
|
46 |
| -public class Paginator implements AutoCloseable |
| 41 | +public class Paginator |
47 | 42 | {
|
48 | 43 | private static final Logger LOGGER = LoggerFactory.getLogger(Paginator.class);
|
49 | 44 | private static final double R_DOUBLE_NA = Double.longBitsToDouble(0x7ff00000000007a2L);
|
50 | 45 | private static final int R_INT_NA = Integer.MIN_VALUE;
|
51 | 46 |
|
52 |
| - private final BlockingQueue<DataPoint> queue = new ArrayBlockingQueue<>(1000); |
53 | 47 | private final DataSetMetadata dataStructure;
|
| 48 | + private final Iterator<DataPoint> iterator; |
| 49 | + private final DataStructureComponent<?, ?, ?>[] comps; |
| 50 | + private final int[] types; |
| 51 | + private final int size; |
| 52 | + private final Object[] result; |
54 | 53 |
|
55 |
| - private boolean closed = false; |
56 |
| - private RuntimeException lastException = null; |
57 | 54 |
|
58 |
| - public Paginator(DataSet dataset) |
| 55 | + public Paginator(DataSet dataset, int size) |
59 | 56 | {
|
| 57 | + this.size = size; |
60 | 58 | dataStructure = dataset.getMetadata();
|
61 |
| - Thread thread = new Thread(() -> { |
62 |
| - try (Stream<DataPoint> stream = dataset.stream()) |
63 |
| - { |
64 |
| - for (DataPoint dp: (Iterable<DataPoint>) stream::iterator) |
65 |
| - while (!isClosed()) |
66 |
| - try |
67 |
| - { |
68 |
| - queue.put(dp); |
69 |
| - break; |
70 |
| - } |
71 |
| - catch (InterruptedException e) |
72 |
| - { |
73 |
| - close(); |
74 |
| - Thread.currentThread().interrupt(); |
75 |
| - } |
76 |
| - } |
77 |
| - catch (Throwable t) |
78 |
| - { |
79 |
| - LOGGER.error(t.getMessage(), t); |
80 |
| - } |
81 |
| - finally |
82 |
| - { |
83 |
| - close(); |
84 |
| - } |
85 |
| - }); |
86 |
| - thread.setDaemon(true); |
87 |
| - thread.start(); |
| 59 | + comps = dataStructure.stream().toArray(DataStructureComponent<?, ?, ?>[]::new); |
| 60 | + result = new Object[comps.length]; |
| 61 | + types = new int[comps.length]; |
| 62 | + for (int i = 0; i < comps.length; i++) |
| 63 | + { |
| 64 | + if (comps[i].getVariable().getDomain() instanceof NumberDomain) |
| 65 | + types[i] = 1; |
| 66 | + else if (comps[i].getVariable().getDomain() instanceof BooleanDomain) |
| 67 | + types[i] = 2; |
| 68 | + else if (comps[i].getVariable().getDomain() instanceof DateDomain) |
| 69 | + types[i] = 3; |
| 70 | + else // StringDomain, TimeDomain, TimePeriodDomain |
| 71 | + types[i] = 4; |
| 72 | + } |
| 73 | + |
| 74 | + try (Stream<DataPoint> stream = dataset.stream()) |
| 75 | + { |
| 76 | + iterator = stream.iterator(); |
| 77 | + } |
88 | 78 | }
|
89 | 79 |
|
90 |
| - public boolean isClosed() |
| 80 | + public DataSetMetadata getDataStructure() |
91 | 81 | {
|
92 |
| - return closed; |
| 82 | + return dataStructure; |
93 | 83 | }
|
94 | 84 |
|
95 |
| - @Override |
96 |
| - public void close() |
| 85 | + public int getType(int i) |
97 | 86 | {
|
98 |
| - closed = true; |
| 87 | + return types[i]; |
99 | 88 | }
|
100 | 89 |
|
101 |
| - public DataSetMetadata getDataStructure() |
| 90 | + public String getName(int i) |
102 | 91 | {
|
103 |
| - return dataStructure; |
| 92 | + return comps[i].getVariable().getName(); |
104 | 93 | }
|
105 | 94 |
|
106 |
| - public List<DataPoint> moreDataPoints() |
| 95 | + public int[] getIntColumn(int i) |
107 | 96 | {
|
108 |
| - return moreDataPoints(20); |
| 97 | + return (int[]) result[i]; |
109 | 98 | }
|
110 |
| - |
111 |
| - public List<DataPoint> moreDataPoints(int size) |
| 99 | + |
| 100 | + public double[] getDoubleColumn(int i) |
112 | 101 | {
|
113 |
| - List<DataPoint> result = new ArrayList<>(); |
114 |
| - |
115 |
| - while ((!isClosed() || !queue.isEmpty()) && (size <= 0 || result.size() < size)) |
116 |
| - try |
117 |
| - { |
118 |
| - DataPoint element = queue.poll(1, SECONDS); |
119 |
| - if (element != null) |
120 |
| - result.add(element); |
121 |
| - } |
122 |
| - catch (InterruptedException e) |
123 |
| - { |
124 |
| - close(); |
125 |
| - Thread.currentThread().interrupt(); |
126 |
| - } |
127 |
| - |
128 |
| - if (lastException != null) |
129 |
| - throw lastException; |
130 |
| - |
131 |
| - return result; |
| 102 | + return (double[]) result[i]; |
132 | 103 | }
|
133 |
| - |
134 |
| - public Map<String, Object> more() |
| 104 | + |
| 105 | + public String[] getStringColumn(int i) |
135 | 106 | {
|
136 |
| - return more(20); |
| 107 | + return (String[]) result[i]; |
137 | 108 | }
|
138 |
| - |
139 |
| - public Map<String, Object> more(int size) |
| 109 | + |
| 110 | + public void prepareMore() |
140 | 111 | {
|
141 |
| - List<DataPoint> datapoints = moreDataPoints(size); |
142 |
| - Map<String, Object> result = new HashMap<>(); |
| 112 | + ArrayList<DataPoint> dps = new ArrayList<>(size); |
| 113 | + for (int i = 0; i < size && iterator.hasNext(); i++) |
| 114 | + dps.add(iterator.next()); |
| 115 | + |
| 116 | + int newSize = dps.size(); |
| 117 | + |
| 118 | + LOGGER.info("Retrieving {} rows from dataset.", newSize); |
143 | 119 |
|
144 |
| - for (DataStructureComponent<?, ?, ?> c: dataStructure) |
145 |
| - if (c.getVariable().getDomain() instanceof NumberDomain) |
| 120 | + boolean test = result[0] == null; |
| 121 | + if (!test) |
| 122 | + switch (types[0]) |
146 | 123 | {
|
147 |
| - double[] array = (double[]) result.computeIfAbsent(c.getVariable().getName(), n -> new double[datapoints.size()]); |
148 |
| - for (int i = 0; i < datapoints.size(); i++) |
149 |
| - { |
150 |
| - Serializable v = datapoints.get(i).get(c).get(); |
151 |
| - array[i] = v == null ? R_DOUBLE_NA : ((Number) v).doubleValue(); |
152 |
| - } |
| 124 | + case 1: test = ((double[]) result[0]).length != newSize; break; |
| 125 | + case 2: |
| 126 | + case 3: test = ((int[]) result[0]).length != newSize; break; |
| 127 | + case 4: test = ((String[]) result[0]).length != newSize; break; |
153 | 128 | }
|
154 |
| - else if (c.getVariable().getDomain() instanceof BooleanDomain || c.getVariable().getDomain() instanceof DateDomain) |
155 |
| - { |
156 |
| - int[] array = (int[]) result.computeIfAbsent(c.getVariable().getName(), n -> new int[datapoints.size()]); |
157 |
| - for (int i = 0; i < datapoints.size(); i++) |
| 129 | + if (test) |
| 130 | + for (int i = 0; i < comps.length; i++) |
| 131 | + switch (types[i]) |
158 | 132 | {
|
159 |
| - Serializable v = datapoints.get(i).get(c).get(); |
160 |
| - if (v == null) |
161 |
| - array[i] = R_INT_NA; |
162 |
| - else if (c.getVariable().getDomain() instanceof BooleanDomain) |
163 |
| - array[i] = (Boolean) v ? 1 : 0; |
164 |
| - else |
165 |
| - array[i] = (int) DAYS.between(LocalDate.of(1970, 1, 1), (LocalDate) v); |
| 133 | + case 1: result[i] = new double[newSize]; break; |
| 134 | + case 2: result[i] = new int[newSize]; break; |
| 135 | + case 3: result[i] = new int[newSize]; break; |
| 136 | + case 4: result[i] = new String[newSize]; break; |
| 137 | + default: throw new IllegalStateException(); |
166 | 138 | }
|
167 |
| - } |
168 |
| - else // StringDomain, TimeDomain, TimePeriodDomain |
| 139 | + |
| 140 | + for (int i = 0; i < result.length; i++) |
| 141 | + { |
| 142 | + Object array = result[i]; |
| 143 | + for (int j = 0; j < newSize; j++) |
169 | 144 | {
|
170 |
| - String[] array = (String[]) result.computeIfAbsent(c.getVariable().getName(), n -> new String[datapoints.size()]); |
171 |
| - for (int i = 0; i < datapoints.size(); i++) |
| 145 | + Serializable value = dps.get(j).get(comps[i]).get(); |
| 146 | + switch (types[i]) |
172 | 147 | {
|
173 |
| - Serializable v = datapoints.get(i).get(c).get(); |
174 |
| - array[i] = v == null ? null : v.toString(); |
| 148 | + case 1: ((double[]) array)[j] = value == null ? R_DOUBLE_NA : ((Number) value).doubleValue(); break; |
| 149 | + case 2: ((int[]) array)[j] = value == null ? R_INT_NA : value == Boolean.TRUE ? 1 : 0; break; |
| 150 | + case 3: ((int[]) array)[j] = value == null ? R_INT_NA : (int) DAYS.between(LocalDate.of(1970, 1, 1), (LocalDate) value); break; |
| 151 | + case 4: ((String[]) array)[j] = value == null ? null : value.toString(); break; |
175 | 152 | }
|
176 |
| - } |
177 |
| - |
178 |
| - return result; |
| 153 | + } |
| 154 | + } |
| 155 | + |
| 156 | + LOGGER.debug("Retrieving {} rows from dataset finished.", newSize); |
179 | 157 | }
|
180 | 158 | }
|
0 commit comments