svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.impl / src / main / java / org / gvsig / fmap / dal / feature / paging / impl / FeaturePagingHelperImpl.java @ 44488
History | View | Annotate | Download (33.4 KB)
1 | 40559 | jjdelcerro | /**
|
---|---|---|---|
2 | * gvSIG. Desktop Geographic Information System.
|
||
3 | 40435 | jjdelcerro | *
|
4 | 40559 | jjdelcerro | * Copyright (C) 2007-2013 gvSIG Association.
|
5 | 40435 | jjdelcerro | *
|
6 | * This program is free software; you can redistribute it and/or
|
||
7 | * modify it under the terms of the GNU General Public License
|
||
8 | 40559 | jjdelcerro | * as published by the Free Software Foundation; either version 3
|
9 | 40435 | jjdelcerro | * of the License, or (at your option) any later version.
|
10 | *
|
||
11 | * This program is distributed in the hope that it will be useful,
|
||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
14 | * GNU General Public License for more details.
|
||
15 | *
|
||
16 | * You should have received a copy of the GNU General Public License
|
||
17 | * along with this program; if not, write to the Free Software
|
||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||
19 | * MA 02110-1301, USA.
|
||
20 | *
|
||
21 | 40559 | jjdelcerro | * For any additional information, do not hesitate to contact us
|
22 | * at info AT gvsig.com, or visit our website www.gvsig.com.
|
||
23 | 40435 | jjdelcerro | */
|
24 | package org.gvsig.fmap.dal.feature.paging.impl; |
||
25 | |||
26 | 43660 | jjdelcerro | import java.util.ArrayList; |
27 | 41212 | jjdelcerro | import java.util.Collection; |
28 | 43660 | jjdelcerro | import java.util.Date; |
29 | 41212 | jjdelcerro | import java.util.Iterator; |
30 | import java.util.List; |
||
31 | import java.util.ListIterator; |
||
32 | 44253 | jjdelcerro | import java.util.logging.Level; |
33 | 40435 | jjdelcerro | import org.slf4j.Logger; |
34 | import org.slf4j.LoggerFactory; |
||
35 | |||
36 | import org.gvsig.fmap.dal.exception.DataException; |
||
37 | import org.gvsig.fmap.dal.feature.EditableFeature; |
||
38 | import org.gvsig.fmap.dal.feature.Feature; |
||
39 | import org.gvsig.fmap.dal.feature.FeatureQuery; |
||
40 | import org.gvsig.fmap.dal.feature.FeatureSelection; |
||
41 | import org.gvsig.fmap.dal.feature.FeatureSet; |
||
42 | import org.gvsig.fmap.dal.feature.FeatureStore; |
||
43 | import org.gvsig.fmap.dal.feature.FeatureType; |
||
44 | 41819 | fdiaz | import org.gvsig.fmap.dal.feature.exception.ConcurrentDataModificationException; |
45 | 40435 | jjdelcerro | import org.gvsig.fmap.dal.feature.exception.FeatureIndexException; |
46 | 42775 | jjdelcerro | import org.gvsig.fmap.dal.feature.impl.dynobjectutils.DynObjectFeatureFacade; |
47 | import org.gvsig.fmap.dal.feature.paging.FacadeOfAFeaturePagingHelper; |
||
48 | 40435 | jjdelcerro | import org.gvsig.fmap.dal.feature.paging.FeaturePagingHelper; |
49 | import org.gvsig.tools.dynobject.DynObject; |
||
50 | import org.gvsig.tools.dynobject.DynObjectSet; |
||
51 | import org.gvsig.tools.dynobject.impl.DefaultDynObjectPagingHelper; |
||
52 | import org.gvsig.tools.exception.BaseException; |
||
53 | 44253 | jjdelcerro | import org.gvsig.tools.util.UnmodifiableBasicList; |
54 | import org.gvsig.tools.util.UnmodifiableBasicList64; |
||
55 | 40435 | jjdelcerro | import org.gvsig.tools.visitor.VisitCanceledException; |
56 | import org.gvsig.tools.visitor.Visitor; |
||
57 | |||
58 | /**
|
||
59 | * Helper class to access the values of a FeatureCollection by position. Handles
|
||
60 | * pagination automatically to avoid filling the memory in case of big
|
||
61 | * collections.
|
||
62 | 41819 | fdiaz | *
|
63 | 40435 | jjdelcerro | * TODO: evaluate if its more convenient to read values in the background when
|
64 | * the returned value is near the end of the page, instead of loading a page on
|
||
65 | * demand.
|
||
66 | 41819 | fdiaz | *
|
67 | 40435 | jjdelcerro | * @author gvSIG Team
|
68 | */
|
||
69 | public class FeaturePagingHelperImpl extends DefaultDynObjectPagingHelper |
||
70 | implements FeaturePagingHelper {
|
||
71 | |||
72 | 43660 | jjdelcerro | private static final Logger LOG = LoggerFactory.getLogger(FeaturePagingHelperImpl.class); |
73 | 40435 | jjdelcerro | |
74 | 43660 | jjdelcerro | private static class Page { |
75 | |||
76 | 43691 | jjdelcerro | private Feature[] features; |
77 | 43660 | jjdelcerro | private final long number; |
78 | private final int size; |
||
79 | private long lastaccess; |
||
80 | |||
81 | public Page(long number, int size) { |
||
82 | this.size = size;
|
||
83 | this.number = number;
|
||
84 | this.features = new Feature[size]; |
||
85 | this.lastaccess = 0; |
||
86 | } |
||
87 | |||
88 | public void setFeature(int i, Feature copy) { |
||
89 | this.features[i] = copy;
|
||
90 | } |
||
91 | |||
92 | public Feature[] getFeatures() { |
||
93 | this.lastaccess = (new Date()).getTime(); |
||
94 | return this.features; |
||
95 | } |
||
96 | |||
97 | public long getPageNumber() { |
||
98 | return this.number; |
||
99 | } |
||
100 | |||
101 | public long getLastAccess() { |
||
102 | return this.lastaccess; |
||
103 | } |
||
104 | |||
105 | public int size() { |
||
106 | return this.size; |
||
107 | } |
||
108 | 43691 | jjdelcerro | |
109 | public void dispose() { |
||
110 | for (int i = 0; i < features.length; i++) { |
||
111 | features[i] = null;
|
||
112 | } |
||
113 | this.features = null; |
||
114 | this.lastaccess = 0; |
||
115 | } |
||
116 | 43660 | jjdelcerro | } |
117 | |||
118 | private static class PageCache { |
||
119 | |||
120 | private final int maxpages; |
||
121 | 43691 | jjdelcerro | private List<Page> pages; |
122 | 43660 | jjdelcerro | |
123 | public PageCache(int maxpages) { |
||
124 | this.maxpages = maxpages;
|
||
125 | this.pages = new ArrayList<>(); |
||
126 | } |
||
127 | |||
128 | 43691 | jjdelcerro | public void clear() { |
129 | for (Page page : pages) {
|
||
130 | page.dispose(); |
||
131 | } |
||
132 | this.pages = new ArrayList<>(); |
||
133 | } |
||
134 | |||
135 | 43660 | jjdelcerro | public Page get(long pageNumber) { |
136 | for( Page page : pages ) {
|
||
137 | if( page.getPageNumber() == pageNumber ) {
|
||
138 | return page;
|
||
139 | } |
||
140 | } |
||
141 | return null; |
||
142 | } |
||
143 | |||
144 | public void add(Page page) { |
||
145 | if( this.pages.size()< this.maxpages ) { |
||
146 | this.pages.add(page);
|
||
147 | return;
|
||
148 | } |
||
149 | int toDrop = 0; |
||
150 | for( int i=0; i<this.pages.size(); i++ ) { |
||
151 | if( this.pages.get(i).getLastAccess()<this.pages.get(toDrop).getLastAccess() ) { |
||
152 | toDrop = i; |
||
153 | } |
||
154 | } |
||
155 | this.pages.set(toDrop, page);
|
||
156 | } |
||
157 | } |
||
158 | |||
159 | 40435 | jjdelcerro | private FeatureQuery query;
|
160 | |||
161 | private FeatureStore featureStore;
|
||
162 | |||
163 | /** If the selected Features must be returned as the first ones. **/
|
||
164 | private boolean selectionUp = false; |
||
165 | |||
166 | private FeatureSet featSet = null; |
||
167 | private FeatureSelection initialSelection = null; |
||
168 | |||
169 | private Feature[] features = null; |
||
170 | 43660 | jjdelcerro | private PageCache cachedPages = null; |
171 | 40435 | jjdelcerro | |
172 | 41212 | jjdelcerro | private boolean initialization_completed = false; |
173 | 42807 | jjdelcerro | |
174 | private FeatureSelection selection = null; |
||
175 | 40435 | jjdelcerro | /**
|
176 | * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
|
||
177 | 41819 | fdiaz | *
|
178 | 40435 | jjdelcerro | * @param featureStore
|
179 | * to extract data from
|
||
180 | * @throws DataException
|
||
181 | * if there is an error initializing the helper
|
||
182 | */
|
||
183 | public FeaturePagingHelperImpl(FeatureStore featureStore)
|
||
184 | throws BaseException {
|
||
185 | this(featureStore, DEFAULT_PAGE_SIZE);
|
||
186 | } |
||
187 | |||
188 | /**
|
||
189 | * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
|
||
190 | 41819 | fdiaz | *
|
191 | 40435 | jjdelcerro | * @param featureStore
|
192 | * to extract data from
|
||
193 | * @param pageSize
|
||
194 | * the number of elements per page data
|
||
195 | * @throws DataException
|
||
196 | * if there is an error initializing the helper
|
||
197 | */
|
||
198 | public FeaturePagingHelperImpl(FeatureStore featureStore, int pageSize) |
||
199 | throws BaseException {
|
||
200 | this(featureStore, null, pageSize); |
||
201 | } |
||
202 | |||
203 | /**
|
||
204 | * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
|
||
205 | 41819 | fdiaz | *
|
206 | 40435 | jjdelcerro | * @param featureStore
|
207 | * to extract data from
|
||
208 | * @throws DataException
|
||
209 | * if there is an error initializing the helper
|
||
210 | */
|
||
211 | public FeaturePagingHelperImpl(FeatureStore featureStore,
|
||
212 | FeatureQuery featureQuery) throws BaseException {
|
||
213 | this(featureStore, featureQuery, DEFAULT_PAGE_SIZE);
|
||
214 | } |
||
215 | |||
216 | /**
|
||
217 | * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
|
||
218 | 41819 | fdiaz | *
|
219 | 40435 | jjdelcerro | * @param featureSet
|
220 | * to extract data from
|
||
221 | * @param pageSize
|
||
222 | * the number of elements per page data
|
||
223 | * @throws DataException
|
||
224 | * if there is an error initializing the helper
|
||
225 | */
|
||
226 | public FeaturePagingHelperImpl(FeatureStore featureStore,
|
||
227 | FeatureQuery featureQuery, int pageSize) throws BaseException { |
||
228 | super();
|
||
229 | 43660 | jjdelcerro | this.cachedPages = new PageCache(3); |
230 | 40435 | jjdelcerro | FeatureQuery query = featureQuery; |
231 | if (featureQuery == null) { |
||
232 | query = featureStore.createFeatureQuery(); |
||
233 | query.setFeatureType(featureStore.getDefaultFeatureType()); |
||
234 | } |
||
235 | |||
236 | this.featureStore = featureStore;
|
||
237 | this.query = query;
|
||
238 | this.query.setPageSize(pageSize);
|
||
239 | |||
240 | setDefaultCalculator(new Sizeable() {
|
||
241 | public long getSize() { |
||
242 | FeatureSet featureSet = getFeatureSet(false);
|
||
243 | try {
|
||
244 | return featureSet.getSize();
|
||
245 | } catch (BaseException e) {
|
||
246 | LOG.error("Error getting the size of the FeatureSet: "
|
||
247 | + featureSet, e); |
||
248 | return 0l; |
||
249 | } |
||
250 | } |
||
251 | }, pageSize); |
||
252 | 41819 | fdiaz | |
253 | |||
254 | 40595 | jldominguez | if (LOG.isDebugEnabled()) {
|
255 | 41819 | fdiaz | |
256 | 40595 | jldominguez | LOG.debug("FeaturePagingHelperImpl created with {} pages, "
|
257 | + "and a page size of {}", new Long(getCalculator() |
||
258 | .getNumPages()), new Integer(pageSize)); |
||
259 | } |
||
260 | 41212 | jjdelcerro | this.initialization_completed = true; |
261 | 40435 | jjdelcerro | } |
262 | |||
263 | /**
|
||
264 | * @return the selectionUp status
|
||
265 | */
|
||
266 | 41630 | jjdelcerro | public boolean isSelectionUp() { |
267 | 40435 | jjdelcerro | return selectionUp;
|
268 | } |
||
269 | 42807 | jjdelcerro | |
270 | public FeatureSelection getSelection() {
|
||
271 | if (selection == null) { |
||
272 | try {
|
||
273 | return getFeatureStore().getFeatureSelection();
|
||
274 | } catch (Exception e) { |
||
275 | LOG.warn("Error getting the selection", e);
|
||
276 | } |
||
277 | } |
||
278 | return selection;
|
||
279 | } |
||
280 | |||
281 | public void setSelection(FeatureSelection selection) { |
||
282 | this.selection = selection;
|
||
283 | } |
||
284 | |||
285 | @Override
|
||
286 | 40435 | jjdelcerro | public void setSelectionUp(boolean selectionUp) { |
287 | this.selectionUp = selectionUp;
|
||
288 | try {
|
||
289 | 43728 | jjdelcerro | this.cachedPages.clear();
|
290 | 42807 | jjdelcerro | FeatureSelection currentSelection = getSelection(); |
291 | 41630 | jjdelcerro | if (selectionUp && !currentSelection.isEmpty()) {
|
292 | initialSelection =(FeatureSelection) currentSelection.clone(); |
||
293 | 40435 | jjdelcerro | setCalculator(new OneSubsetOneSetPagingCalculator(
|
294 | new FeatureSetSizeableDelegate(initialSelection),
|
||
295 | new FeatureSetSizeableDelegate(getFeatureSet(false)), |
||
296 | getMaxPageSize())); |
||
297 | } else {
|
||
298 | if (initialSelection != null) { |
||
299 | initialSelection.dispose(); |
||
300 | initialSelection = null;
|
||
301 | } |
||
302 | setDefaultCalculator(new FeatureSetSizeableDelegate(
|
||
303 | getFeatureSet(false)), getMaxPageSize());
|
||
304 | } |
||
305 | } catch (BaseException e) {
|
||
306 | LOG.error("Error setting the selection up setting to: "
|
||
307 | + selectionUp, e); |
||
308 | } catch (CloneNotSupportedException e) { |
||
309 | LOG.error("Error cloning the selection "
|
||
310 | + "while setting the selection up", e);
|
||
311 | } |
||
312 | } |
||
313 | |||
314 | 42991 | jbadia | public synchronized Feature getFeatureAt(long index) throws BaseException { |
315 | 40435 | jjdelcerro | // Check if we have currently loaded the viewed page data,
|
316 | // or we need to load a new one
|
||
317 | 42991 | jbadia | int maxPageSize = getMaxPageSize();
|
318 | long currentPage = getCurrentPage();
|
||
319 | long currentPage2 = currentPage;
|
||
320 | |||
321 | |||
322 | long pageForIndex = (long) Math.floor(index / maxPageSize); |
||
323 | 40435 | jjdelcerro | |
324 | 42991 | jbadia | if (pageForIndex != currentPage) {
|
325 | 40435 | jjdelcerro | setCurrentPage(pageForIndex); |
326 | 42991 | jbadia | currentPage2 = getCurrentPage(); |
327 | 40435 | jjdelcerro | } |
328 | |||
329 | 42991 | jbadia | long positionForIndex = index - (currentPage2 * maxPageSize);
|
330 | 40435 | jjdelcerro | |
331 | 41268 | jjdelcerro | if (positionForIndex >= getCurrentPageFeatures().length) {
|
332 | 40435 | jjdelcerro | throw new FeatureIndexException( |
333 | new IndexOutOfBoundsException("positionForIndex too big: " |
||
334 | + positionForIndex)); |
||
335 | } else {
|
||
336 | 41268 | jjdelcerro | Feature feature = getCurrentPageFeatures()[(int) positionForIndex];
|
337 | 41212 | jjdelcerro | return feature;
|
338 | 40435 | jjdelcerro | } |
339 | 41819 | fdiaz | |
340 | 40435 | jjdelcerro | } |
341 | |||
342 | public Feature[] getCurrentPageFeatures() { |
||
343 | 41268 | jjdelcerro | if( this.features==null ) { |
344 | try {
|
||
345 | this.loadCurrentPageData();
|
||
346 | } catch (BaseException ex) {
|
||
347 | // Do nothing
|
||
348 | } |
||
349 | if( this.features == null ) { |
||
350 | String msg = "Can't retrieve the features from current page."; |
||
351 | LOG.warn(msg); |
||
352 | throw new RuntimeException(msg); |
||
353 | } |
||
354 | } |
||
355 | 40435 | jjdelcerro | return features;
|
356 | } |
||
357 | |||
358 | /**
|
||
359 | * Gets the feature set.
|
||
360 | * The boolean tells whether we must create the featureset
|
||
361 | * again (for example perhaps we need it after a feature
|
||
362 | * has been added/removed)
|
||
363 | */
|
||
364 | private FeatureSet getFeatureSet(boolean reset) { |
||
365 | 41819 | fdiaz | |
366 | 40435 | jjdelcerro | if (featSet == null || reset) { |
367 | 41819 | fdiaz | |
368 | 40435 | jjdelcerro | if (featSet != null) { |
369 | try {
|
||
370 | featSet.dispose(); |
||
371 | } catch (Exception ex) { |
||
372 | LOG.info("Error while disposing featset.", ex);
|
||
373 | } |
||
374 | } |
||
375 | 41819 | fdiaz | |
376 | 40435 | jjdelcerro | try {
|
377 | 41819 | fdiaz | FeatureStore featureStore = getFeatureStore(); |
378 | 40435 | jjdelcerro | synchronized (featureStore) {
|
379 | 41819 | fdiaz | featSet = featureStore.getFeatureSet(getFeatureQuery()); |
380 | 40435 | jjdelcerro | } |
381 | } catch (DataException e) {
|
||
382 | throw new RuntimeException("Error getting a feature set with the query " + getFeatureQuery()); |
||
383 | } |
||
384 | } |
||
385 | return featSet;
|
||
386 | } |
||
387 | 41819 | fdiaz | |
388 | 43691 | jjdelcerro | @Override
|
389 | 40435 | jjdelcerro | public DynObjectSet getDynObjectSet() {
|
390 | return getFeatureSet(false).getDynObjectSet(); |
||
391 | } |
||
392 | |||
393 | 43691 | jjdelcerro | @Override
|
394 | 40435 | jjdelcerro | public void reloadCurrentPage() throws BaseException { |
395 | 41819 | fdiaz | |
396 | 40435 | jjdelcerro | boolean sel_up = this.isSelectionUp(); |
397 | |||
398 | setSelectionUp(false);
|
||
399 | if (getCalculator().getCurrentPage() > -1) { |
||
400 | 43691 | jjdelcerro | this.cachedPages.clear();
|
401 | 40435 | jjdelcerro | loadCurrentPageData(); |
402 | } |
||
403 | 41819 | fdiaz | |
404 | 40435 | jjdelcerro | if (sel_up) {
|
405 | setSelectionUp(true);
|
||
406 | } |
||
407 | } |
||
408 | |||
409 | 43691 | jjdelcerro | @Override
|
410 | 40435 | jjdelcerro | public void reload() throws BaseException { |
411 | 41819 | fdiaz | |
412 | 43726 | jjdelcerro | this.cachedPages.clear();
|
413 | 40435 | jjdelcerro | /*
|
414 | * Force re-creation of feature set
|
||
415 | */
|
||
416 | this.getFeatureSet(true); |
||
417 | |||
418 | 41819 | fdiaz | |
419 | 40435 | jjdelcerro | setDefaultCalculator(new Sizeable() {
|
420 | public long getSize() { |
||
421 | FeatureSet featureSet = getFeatureSet(false);
|
||
422 | try {
|
||
423 | return featureSet.getSize();
|
||
424 | } catch (BaseException e) {
|
||
425 | LOG.error("Error getting the size of the FeatureSet: "
|
||
426 | + featureSet, e); |
||
427 | return 0l; |
||
428 | } |
||
429 | } |
||
430 | }, getCalculator().getMaxPageSize()); |
||
431 | reloadCurrentPage(); |
||
432 | } |
||
433 | |||
434 | public FeatureStore getFeatureStore() {
|
||
435 | return featureStore;
|
||
436 | } |
||
437 | |||
438 | public FeatureQuery getFeatureQuery() {
|
||
439 | return query;
|
||
440 | } |
||
441 | |||
442 | /**
|
||
443 | * Loads all the Features of the current page.
|
||
444 | 43660 | jjdelcerro | * @throws org.gvsig.tools.exception.BaseException
|
445 | 40435 | jjdelcerro | */
|
446 | 43660 | jjdelcerro | @Override
|
447 | 42991 | jbadia | protected synchronized void loadCurrentPageData() throws BaseException { |
448 | 41212 | jjdelcerro | if( !initialization_completed ) {
|
449 | return;
|
||
450 | } |
||
451 | 40435 | jjdelcerro | final int currentPageSize = getCalculator().getCurrentPageSize(); |
452 | 43660 | jjdelcerro | final long currentPage = getCalculator().getCurrentPage(); |
453 | Page page = this.cachedPages.get(currentPage);
|
||
454 | if( page==null ) { |
||
455 | page = new Page(currentPage, currentPageSize);
|
||
456 | 40435 | jjdelcerro | |
457 | 43660 | jjdelcerro | long t1 = 0; |
458 | if (LOG.isTraceEnabled()) {
|
||
459 | t1 = System.currentTimeMillis();
|
||
460 | } |
||
461 | 40435 | jjdelcerro | |
462 | 43660 | jjdelcerro | if (selectionUp) {
|
463 | loadCurrentPageDataWithSelectionUp(page); |
||
464 | } else {
|
||
465 | loadCurrentPageDataNoSelection(page); |
||
466 | } |
||
467 | 40435 | jjdelcerro | |
468 | 43660 | jjdelcerro | if (LOG.isTraceEnabled()) {
|
469 | long t2 = System.currentTimeMillis(); |
||
470 | LOG.trace("Time to load {} features: {} ms", currentPageSize, t2 - t1);
|
||
471 | } |
||
472 | this.cachedPages.add(page);
|
||
473 | 40435 | jjdelcerro | } |
474 | 43660 | jjdelcerro | this.features = page.getFeatures();
|
475 | 40435 | jjdelcerro | } |
476 | 41819 | fdiaz | |
477 | 43660 | jjdelcerro | private void loadCurrentPageDataWithSelectionUp(final Page page) |
478 | 41630 | jjdelcerro | throws BaseException {
|
479 | 40435 | jjdelcerro | FeatureSelection selection = initialSelection; |
480 | 41630 | jjdelcerro | if (selection == null) { |
481 | 43660 | jjdelcerro | loadCurrentPageDataNoSelection(page); |
482 | 41630 | jjdelcerro | } else {
|
483 | FeatureSet set = getFeatureSet(false);
|
||
484 | try {
|
||
485 | OneSubsetOneSetPagingCalculator twoSetsCalculator = null;
|
||
486 | if (getCalculator() instanceof OneSubsetOneSetPagingCalculator) { |
||
487 | twoSetsCalculator |
||
488 | = (OneSubsetOneSetPagingCalculator) getCalculator(); |
||
489 | } else {
|
||
490 | twoSetsCalculator |
||
491 | = new OneSubsetOneSetPagingCalculator(
|
||
492 | new FeatureSetSizeableDelegate(selection),
|
||
493 | new FeatureSetSizeableDelegate(set),
|
||
494 | getMaxPageSize(), getCalculator().getCurrentPage()); |
||
495 | setCalculator(twoSetsCalculator); |
||
496 | } |
||
497 | 40435 | jjdelcerro | |
498 | // First load values from the selection, if the current page has
|
||
499 | 41630 | jjdelcerro | // elements from it
|
500 | if (twoSetsCalculator.hasCurrentPageAnyValuesInFirstSet()) {
|
||
501 | 43660 | jjdelcerro | loadDataFromFeatureSet(page, 0, selection,
|
502 | 41630 | jjdelcerro | twoSetsCalculator.getFirstSetInitialIndex(), |
503 | twoSetsCalculator.getFirstSetHowMany(), null);
|
||
504 | } |
||
505 | 40435 | jjdelcerro | // Next, load values from the FeatureSet if the current page has values
|
506 | 41630 | jjdelcerro | // from it
|
507 | if (twoSetsCalculator.hasCurrentPageAnyValuesInSecondSet()) {
|
||
508 | loadDataFromFeatureSet( |
||
509 | 43660 | jjdelcerro | page, |
510 | 41630 | jjdelcerro | // The cast will work as that size will be <= maxpagesize,
|
511 | // which is an int
|
||
512 | (int) twoSetsCalculator.getFirstSetHowMany(), set,
|
||
513 | twoSetsCalculator.getSecondSetInitialIndex(), |
||
514 | twoSetsCalculator.getSecondSetHowMany(), selection); |
||
515 | } |
||
516 | } finally {
|
||
517 | /*
|
||
518 | * This is the feature set
|
||
519 | * we dont want to lose it
|
||
520 | */
|
||
521 | // set.dispose();
|
||
522 | } |
||
523 | 40435 | jjdelcerro | } |
524 | } |
||
525 | |||
526 | 43660 | jjdelcerro | private void loadCurrentPageDataNoSelection(final Page page) |
527 | 40435 | jjdelcerro | throws BaseException {
|
528 | |||
529 | long firstPosition = getCalculator().getInitialIndex();
|
||
530 | |||
531 | if (LOG.isDebugEnabled()) {
|
||
532 | 43660 | jjdelcerro | LOG.debug("Loading {} Features starting at position {}",
|
533 | getCalculator().getCurrentPageSize(), firstPosition |
||
534 | ); |
||
535 | 40435 | jjdelcerro | } |
536 | |||
537 | FeatureSet featureSet = getFeatureSet(false);
|
||
538 | try {
|
||
539 | 43660 | jjdelcerro | loadDataFromFeatureSet(page, 0, featureSet, firstPosition,
|
540 | 40435 | jjdelcerro | getCalculator().getCurrentPageSize(), null);
|
541 | } catch(DataException ex) {
|
||
542 | throw ex;
|
||
543 | // } finally {
|
||
544 | // featureSet.dispose();
|
||
545 | } |
||
546 | 41819 | fdiaz | |
547 | 40435 | jjdelcerro | } |
548 | |||
549 | 43660 | jjdelcerro | private void loadDataFromFeatureSet(final Page page, |
550 | 40435 | jjdelcerro | final int valuesPosition, FeatureSet set, long initialIndex, |
551 | final long howMany, final FeatureSelection selectedFeaturesToSkip) |
||
552 | throws DataException {
|
||
553 | |||
554 | try {
|
||
555 | set.accept(new Visitor() {
|
||
556 | private int i = valuesPosition; |
||
557 | |||
558 | 43660 | jjdelcerro | @Override
|
559 | 40435 | jjdelcerro | public void visit(Object obj) throws VisitCanceledException, |
560 | BaseException { |
||
561 | if (i >= valuesPosition + howMany) {
|
||
562 | throw new VisitCanceledException(); |
||
563 | } |
||
564 | Feature current = (Feature) obj; |
||
565 | // Add the current Feature only if we don't skip selected
|
||
566 | // features or the feature is not selected
|
||
567 | if (selectedFeaturesToSkip == null |
||
568 | || !selectedFeaturesToSkip.isSelected(current)) { |
||
569 | 41630 | jjdelcerro | try {
|
570 | 43660 | jjdelcerro | page.setFeature(i,current.getCopy()); |
571 | 41630 | jjdelcerro | i++; |
572 | } catch(Exception ex) { |
||
573 | // Aqui no deberia petar, pero...
|
||
574 | // me he encontrado un caso que tenia una referencia a
|
||
575 | 41819 | fdiaz | // una feature seleccionada que ya no existia. No se como
|
576 | 41630 | jjdelcerro | // habia pasado, se habia quedado de antes guardada en el
|
577 | // proyecto pero la feature ya no existia, y eso hacia que
|
||
578 | // petase al intentar leer de disco la feature a partir
|
||
579 | // de una referencia no valida.
|
||
580 | } |
||
581 | 40435 | jjdelcerro | } |
582 | } |
||
583 | 43358 | jjdelcerro | }, initialIndex, howMany); |
584 | } catch(VisitCanceledException ex) {
|
||
585 | // Do nothing
|
||
586 | 40435 | jjdelcerro | } catch (BaseException e) {
|
587 | if (e instanceof DataException) { |
||
588 | throw ((DataException) e);
|
||
589 | } else {
|
||
590 | LOG.error("Error loading the data starting at position {}",
|
||
591 | new Long(initialIndex), e); |
||
592 | } |
||
593 | } |
||
594 | } |
||
595 | |||
596 | public void delete(Feature feature) throws BaseException { |
||
597 | featureStore.delete(feature); |
||
598 | /*
|
||
599 | * Force re-creation of feature set
|
||
600 | */
|
||
601 | this.getFeatureSet(true); |
||
602 | |||
603 | reloadCurrentPage(); |
||
604 | } |
||
605 | |||
606 | public void insert(EditableFeature feature) throws BaseException { |
||
607 | featureStore.insert(feature); |
||
608 | /*
|
||
609 | * Force re-creation of feature set
|
||
610 | */
|
||
611 | this.getFeatureSet(true); |
||
612 | |||
613 | reloadCurrentPage(); |
||
614 | } |
||
615 | 44488 | jjdelcerro | |
616 | public boolean isEmpty() { |
||
617 | try {
|
||
618 | return getFeatureSet(false).isEmpty(); |
||
619 | } catch (ConcurrentDataModificationException ex) {
|
||
620 | LOG.warn("ConcurrentDataModification error asking about the emptiness of the list. Retrying reloading data.");
|
||
621 | try {
|
||
622 | reload(); |
||
623 | } catch (BaseException e) {
|
||
624 | LOG.warn("Error reloading data.", e);
|
||
625 | throw new RuntimeException(e); |
||
626 | } |
||
627 | try {
|
||
628 | return getFeatureSet(false).isEmpty(); |
||
629 | } catch (DataException e) {
|
||
630 | LOG.warn("Error asking about the emptiness of the list after reloading data.",e);
|
||
631 | throw new RuntimeException(e); |
||
632 | } |
||
633 | } catch (DataException ex) {
|
||
634 | throw new RuntimeException(ex); |
||
635 | } |
||
636 | } |
||
637 | 40435 | jjdelcerro | |
638 | public void update(EditableFeature feature) throws BaseException { |
||
639 | featureStore.update(feature); |
||
640 | /*
|
||
641 | * Force re-creation of feature set
|
||
642 | */
|
||
643 | this.getFeatureSet(true); |
||
644 | |||
645 | reloadCurrentPage(); |
||
646 | } |
||
647 | |||
648 | public FeatureType getFeatureType() {
|
||
649 | 41819 | fdiaz | |
650 | 40435 | jjdelcerro | FeatureType ft = null;
|
651 | 41819 | fdiaz | |
652 | 40435 | jjdelcerro | try {
|
653 | ft = featureStore.getDefaultFeatureType(); |
||
654 | } catch (DataException e) {
|
||
655 | LOG.error("Error while getting feature type: " +
|
||
656 | e.getMessage(), e); |
||
657 | } |
||
658 | return ft;
|
||
659 | 41819 | fdiaz | |
660 | 40435 | jjdelcerro | /*
|
661 | 41819 | fdiaz | *
|
662 | 40435 | jjdelcerro | FeatureSet featureSet = getFeatureSet();
|
663 | try {
|
||
664 | return featureSet.getDefaultFeatureType();
|
||
665 | } finally {
|
||
666 | featureSet.dispose();
|
||
667 | }
|
||
668 | */
|
||
669 | |||
670 | 41819 | fdiaz | |
671 | 40435 | jjdelcerro | } |
672 | |||
673 | protected void doDispose() throws BaseException { |
||
674 | initialSelection.dispose(); |
||
675 | if (featSet != null) { |
||
676 | try {
|
||
677 | featSet.dispose(); |
||
678 | } catch (Exception ex) { |
||
679 | LOG.info("Error while disposing featset.", ex);
|
||
680 | } |
||
681 | } |
||
682 | } |
||
683 | |||
684 | public DynObject[] getCurrentPageDynObjects() { |
||
685 | Feature[] features = getCurrentPageFeatures();
|
||
686 | DynObject[] dynobjects = new DynObject[features.length]; |
||
687 | for (int i = 0; i < dynobjects.length; i++) { |
||
688 | dynobjects[i] = new DynObjectFeatureFacade(features[i]);
|
||
689 | } |
||
690 | return dynobjects;
|
||
691 | } |
||
692 | |||
693 | 44253 | jjdelcerro | @Override
|
694 | 40435 | jjdelcerro | public DynObject getDynObjectAt(long index) throws BaseException { |
695 | return new DynObjectFeatureFacade(getFeatureAt(index)); |
||
696 | } |
||
697 | |||
698 | 44253 | jjdelcerro | @Override
|
699 | 41212 | jjdelcerro | public List asList() { |
700 | return new FeaturePagingHelperList(); |
||
701 | } |
||
702 | 41819 | fdiaz | |
703 | 44253 | jjdelcerro | @Override
|
704 | 41212 | jjdelcerro | public List asListOfDynObjects() { |
705 | return new DynObjectPagingHelperList(); |
||
706 | 41819 | fdiaz | } |
707 | |||
708 | 41212 | jjdelcerro | private class FeaturePagingHelperList extends PagingHelperList { |
709 | 44253 | jjdelcerro | @Override
|
710 | 41212 | jjdelcerro | public Object get(int i) { |
711 | 44253 | jjdelcerro | return this.get64(i); |
712 | } |
||
713 | |||
714 | @Override
|
||
715 | public Object get64(long i) { |
||
716 | 41212 | jjdelcerro | try {
|
717 | return getFeatureAt(i);
|
||
718 | 44253 | jjdelcerro | } catch (ConcurrentDataModificationException ex) {
|
719 | LOG.warn("ConcurrentDataModification error getting feature "+i+" of the list. Retrying reloading data."); |
||
720 | try {
|
||
721 | reload(); |
||
722 | } catch (BaseException e) {
|
||
723 | LOG.warn("Error reloading data.", e);
|
||
724 | throw new RuntimeException(e); |
||
725 | } |
||
726 | try {
|
||
727 | return getFeatureAt(i);
|
||
728 | } catch (Exception e) { |
||
729 | LOG.warn("Error getting feature "+i+" of the list after reloading data.",e); |
||
730 | throw new RuntimeException(e); |
||
731 | } |
||
732 | 41212 | jjdelcerro | } catch (BaseException ex) {
|
733 | throw new RuntimeException(ex); |
||
734 | } |
||
735 | } |
||
736 | 44253 | jjdelcerro | |
737 | @Override
|
||
738 | public Object set(int i, Object e) { |
||
739 | // Feature newFeature = (Feature) e;
|
||
740 | // EditableFeature oldFeature = ((Feature) this.get(i)).getEditable();
|
||
741 | // oldFeature.copyFrom(newFeature);
|
||
742 | // update(oldFeature);
|
||
743 | return super.set(i, e); |
||
744 | } |
||
745 | |||
746 | @Override
|
||
747 | public Object remove(int i) { |
||
748 | // Feature feature = (Feature) this.get(i);
|
||
749 | // delete(feature);
|
||
750 | return super.remove(i); |
||
751 | } |
||
752 | |||
753 | @Override
|
||
754 | public boolean add(Object e) { |
||
755 | // EditableFeature feature = (EditableFeature) e;
|
||
756 | // insert(feature);
|
||
757 | return super.add(e); |
||
758 | } |
||
759 | 41212 | jjdelcerro | } |
760 | 41819 | fdiaz | |
761 | 41212 | jjdelcerro | private class DynObjectPagingHelperList extends PagingHelperList { |
762 | 44253 | jjdelcerro | @Override
|
763 | 41212 | jjdelcerro | public Object get(int i) { |
764 | 44253 | jjdelcerro | return this.get64(i); |
765 | } |
||
766 | |||
767 | @Override
|
||
768 | public Object get64(long position) { |
||
769 | 41212 | jjdelcerro | try {
|
770 | 44253 | jjdelcerro | return getDynObjectAt(position);
|
771 | } catch (ConcurrentDataModificationException ex) {
|
||
772 | LOG.warn("ConcurrentDataModification error getting element "+position+" of the list. Retrying reloading data."); |
||
773 | try {
|
||
774 | reload(); |
||
775 | } catch (BaseException e) {
|
||
776 | LOG.warn("Error reloading data.", e);
|
||
777 | throw new RuntimeException(e); |
||
778 | } |
||
779 | try {
|
||
780 | return getDynObjectAt(position);
|
||
781 | } catch (Exception e) { |
||
782 | LOG.warn("Error getting element "+position+" of the list after reloading data.",e); |
||
783 | throw new RuntimeException(e); |
||
784 | } |
||
785 | 41212 | jjdelcerro | } catch (BaseException ex) {
|
786 | throw new RuntimeException(ex); |
||
787 | } |
||
788 | } |
||
789 | 42775 | jjdelcerro | |
790 | 41212 | jjdelcerro | } |
791 | 41819 | fdiaz | |
792 | 44253 | jjdelcerro | private abstract class PagingHelperList implements List, FacadeOfAFeaturePagingHelper, UnmodifiableBasicList, UnmodifiableBasicList64 { |
793 | 41212 | jjdelcerro | |
794 | 42775 | jjdelcerro | @Override
|
795 | public FeaturePagingHelper getFeaturePagingHelper() {
|
||
796 | return FeaturePagingHelperImpl.this;
|
||
797 | } |
||
798 | 44253 | jjdelcerro | |
799 | @Override
|
||
800 | public String toString() { |
||
801 | return String.format("..(%d %ss)...", this.size(), featureStore.getName()); |
||
802 | } |
||
803 | 42775 | jjdelcerro | |
804 | 44253 | jjdelcerro | @Override
|
805 | public long size64() { |
||
806 | 41212 | jjdelcerro | try {
|
807 | 44253 | jjdelcerro | return getFeatureSet(false).getSize(); |
808 | } catch (ConcurrentDataModificationException ex) {
|
||
809 | LOG.warn("ConcurrentDataModification error asking the size of the list. Retrying reloading data.");
|
||
810 | try {
|
||
811 | reload(); |
||
812 | } catch (BaseException e) {
|
||
813 | LOG.warn("Error reloading data.", e);
|
||
814 | throw new RuntimeException(e); |
||
815 | } |
||
816 | try {
|
||
817 | return getFeatureSet(false).getSize(); |
||
818 | } catch (DataException e) {
|
||
819 | LOG.warn("Error asking the size of the list after reloading data.",e);
|
||
820 | throw new RuntimeException(e); |
||
821 | } |
||
822 | 41212 | jjdelcerro | } catch (DataException ex) {
|
823 | throw new RuntimeException(ex); |
||
824 | } |
||
825 | } |
||
826 | |||
827 | 44253 | jjdelcerro | @Override
|
828 | public int size() { |
||
829 | long sz = this.size64(); |
||
830 | if( sz>Integer.MAX_VALUE ) { |
||
831 | sz = Integer.MAX_VALUE;
|
||
832 | } |
||
833 | return (int) sz; |
||
834 | } |
||
835 | |||
836 | @Override
|
||
837 | 41212 | jjdelcerro | public boolean isEmpty() { |
838 | try {
|
||
839 | return getFeatureSet(false).isEmpty(); |
||
840 | 41819 | fdiaz | } catch (ConcurrentDataModificationException ex) {
|
841 | 44253 | jjdelcerro | LOG.warn("ConcurrentDataModification error asking about the emptiness of the list. Retrying reloading data.");
|
842 | 41819 | fdiaz | try {
|
843 | reload(); |
||
844 | } catch (BaseException e) {
|
||
845 | LOG.warn("Error reloading data.", e);
|
||
846 | throw new RuntimeException(e); |
||
847 | } |
||
848 | try {
|
||
849 | return getFeatureSet(false).isEmpty(); |
||
850 | } catch (DataException e) {
|
||
851 | 44253 | jjdelcerro | LOG.warn("Error asking about the emptiness of the list after reloading data.",e);
|
852 | 41819 | fdiaz | throw new RuntimeException(e); |
853 | } |
||
854 | 44253 | jjdelcerro | } catch (DataException ex) {
|
855 | throw new RuntimeException(ex); |
||
856 | 41212 | jjdelcerro | } |
857 | } |
||
858 | |||
859 | 44253 | jjdelcerro | @Override
|
860 | 41212 | jjdelcerro | public Iterator iterator() { |
861 | try {
|
||
862 | return getFeatureSet(false).fastIterator(); |
||
863 | 44253 | jjdelcerro | } catch (ConcurrentDataModificationException ex) {
|
864 | LOG.warn("ConcurrentDataModification error getting iterator of the list. Retrying reloading data.");
|
||
865 | try {
|
||
866 | reload(); |
||
867 | } catch (BaseException e) {
|
||
868 | LOG.warn("Error reloading data.", e);
|
||
869 | throw new RuntimeException(e); |
||
870 | } |
||
871 | try {
|
||
872 | return getFeatureSet(false).fastIterator(); |
||
873 | } catch (DataException e) {
|
||
874 | LOG.warn("Error getting iterator of the list after reloading data.",e);
|
||
875 | throw new RuntimeException(e); |
||
876 | } |
||
877 | 41212 | jjdelcerro | } catch (DataException ex) {
|
878 | throw new RuntimeException(ex); |
||
879 | } |
||
880 | } |
||
881 | |||
882 | 44253 | jjdelcerro | @Override
|
883 | 41212 | jjdelcerro | public boolean contains(Object o) { |
884 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. |
||
885 | } |
||
886 | |||
887 | 44253 | jjdelcerro | @Override
|
888 | 41212 | jjdelcerro | public Object[] toArray() { |
889 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. |
||
890 | } |
||
891 | |||
892 | 44253 | jjdelcerro | @Override
|
893 | 41212 | jjdelcerro | public Object[] toArray(Object[] ts) { |
894 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. |
||
895 | } |
||
896 | |||
897 | 44253 | jjdelcerro | @Override
|
898 | 41212 | jjdelcerro | public boolean add(Object e) { |
899 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. |
||
900 | } |
||
901 | |||
902 | 44253 | jjdelcerro | @Override
|
903 | 41212 | jjdelcerro | public boolean remove(Object o) { |
904 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. |
||
905 | } |
||
906 | |||
907 | 44253 | jjdelcerro | @Override
|
908 | 41212 | jjdelcerro | public boolean containsAll(Collection clctn) { |
909 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. |
||
910 | } |
||
911 | |||
912 | 44253 | jjdelcerro | @Override
|
913 | 41212 | jjdelcerro | public boolean addAll(Collection clctn) { |
914 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. |
||
915 | } |
||
916 | |||
917 | 44253 | jjdelcerro | @Override
|
918 | 41212 | jjdelcerro | public boolean addAll(int i, Collection clctn) { |
919 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. |
||
920 | } |
||
921 | |||
922 | 44253 | jjdelcerro | @Override
|
923 | 41212 | jjdelcerro | public boolean removeAll(Collection clctn) { |
924 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. |
||
925 | } |
||
926 | |||
927 | 44253 | jjdelcerro | @Override
|
928 | 41212 | jjdelcerro | public boolean retainAll(Collection clctn) { |
929 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. |
||
930 | } |
||
931 | |||
932 | 44253 | jjdelcerro | @Override
|
933 | 41212 | jjdelcerro | public void clear() { |
934 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. |
||
935 | } |
||
936 | |||
937 | 44253 | jjdelcerro | @Override
|
938 | 41212 | jjdelcerro | public Object set(int i, Object e) { |
939 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. |
||
940 | } |
||
941 | |||
942 | 44253 | jjdelcerro | @Override
|
943 | 41212 | jjdelcerro | public void add(int i, Object e) { |
944 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. |
||
945 | } |
||
946 | |||
947 | 44253 | jjdelcerro | @Override
|
948 | 41212 | jjdelcerro | public Object remove(int i) { |
949 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. |
||
950 | } |
||
951 | |||
952 | 44253 | jjdelcerro | @Override
|
953 | 41212 | jjdelcerro | public int indexOf(Object o) { |
954 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. |
||
955 | } |
||
956 | |||
957 | 44253 | jjdelcerro | @Override
|
958 | 41212 | jjdelcerro | public int lastIndexOf(Object o) { |
959 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. |
||
960 | } |
||
961 | |||
962 | 44253 | jjdelcerro | @Override
|
963 | 41212 | jjdelcerro | public ListIterator listIterator() { |
964 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. |
||
965 | } |
||
966 | |||
967 | 44253 | jjdelcerro | @Override
|
968 | 41212 | jjdelcerro | public ListIterator listIterator(int i) { |
969 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. |
||
970 | } |
||
971 | |||
972 | 44253 | jjdelcerro | @Override
|
973 | 41212 | jjdelcerro | public List subList(int i, int i1) { |
974 | throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. |
||
975 | } |
||
976 | 41819 | fdiaz | |
977 | 44253 | jjdelcerro | @Override
|
978 | public List toList() { |
||
979 | return this; |
||
980 | } |
||
981 | |||
982 | 41212 | jjdelcerro | } |
983 | 40435 | jjdelcerro | } |