Statistics
| Revision:

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 @ 45425

History | View | Annotate | Download (34 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2020 gvSIG Association.
5
 *
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
 * as published by the Free Software Foundation; either version 3
9
 * 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
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.fmap.dal.feature.paging.impl;
25

    
26
import java.util.ArrayList;
27
import java.util.Collection;
28
import java.util.Date;
29
import java.util.Iterator;
30
import java.util.List;
31
import java.util.ListIterator;
32
import java.util.logging.Level;
33
import org.apache.commons.lang3.mutable.MutableBoolean;
34
import org.slf4j.Logger;
35
import org.slf4j.LoggerFactory;
36

    
37
import org.gvsig.fmap.dal.exception.DataException;
38
import org.gvsig.fmap.dal.feature.EditableFeature;
39
import org.gvsig.fmap.dal.feature.Feature;
40
import org.gvsig.fmap.dal.feature.FeatureQuery;
41
import org.gvsig.fmap.dal.feature.FeatureSelection;
42
import org.gvsig.fmap.dal.feature.FeatureSet;
43
import org.gvsig.fmap.dal.feature.FeatureStore;
44
import org.gvsig.fmap.dal.feature.FeatureType;
45
import org.gvsig.fmap.dal.feature.exception.ConcurrentDataModificationException;
46
import org.gvsig.fmap.dal.feature.exception.FeatureIndexException;
47
import org.gvsig.fmap.dal.feature.impl.dynobjectutils.DynObjectFeatureFacade;
48
import org.gvsig.fmap.dal.feature.paging.FacadeOfAFeaturePagingHelper;
49
import org.gvsig.fmap.dal.feature.paging.FeaturePagingHelper;
50
import org.gvsig.tools.dispose.Disposable;
51
import org.gvsig.tools.dispose.DisposeUtils;
52
import org.gvsig.tools.dynobject.DynObject;
53
import org.gvsig.tools.dynobject.DynObjectSet;
54
import org.gvsig.tools.dynobject.impl.DefaultDynObjectPagingHelper;
55
import org.gvsig.tools.exception.BaseException;
56
import org.gvsig.tools.util.UnmodifiableBasicList;
57
import org.gvsig.tools.util.UnmodifiableBasicList64;
58
import org.gvsig.tools.visitor.VisitCanceledException;
59
import org.gvsig.tools.visitor.Visitor;
60

    
61
/**
62
 * Helper class to access the values of a FeatureCollection by position. Handles
63
 * pagination automatically to avoid filling the memory in case of big
64
 * collections.
65
 *
66
 * TODO: evaluate if its more convenient to read values in the background when
67
 * the returned value is near the end of the page, instead of loading a page on
68
 * demand.
69
 *
70
 * @author gvSIG Team
71
 */
72
@SuppressWarnings("UseSpecificCatch")
73
public class FeaturePagingHelperImpl extends DefaultDynObjectPagingHelper
74
        implements FeaturePagingHelper {
75

    
76
    private static final Logger LOG = LoggerFactory.getLogger(FeaturePagingHelperImpl.class);
77

    
78
    private static class Page {
79

    
80
        private Feature[] features;
81
        private final long number;
82
        private final int size;
83
        private long lastaccess;
84

    
85
        public Page(long number, int size) {
86
            this.size = size;
87
            this.number = number;
88
            this.features = new Feature[size];
89
            this.lastaccess = 0;
90
        }
91

    
92
        public void setFeature(int i, Feature copy) {
93
            this.features[i] = copy;
94
        }
95

    
96
        public Feature[] getFeatures() {
97
            this.lastaccess = (new Date()).getTime();
98
            return this.features;
99
        }
100

    
101
        public long getPageNumber() {
102
            return this.number;
103
        }
104

    
105
        public long getLastAccess() {
106
            return this.lastaccess;
107
        }
108

    
109
        public int size() {
110
            return this.size;
111
        }
112

    
113
        public void dispose() {
114
            for (int i = 0; i < features.length; i++) {
115
                features[i] = null;
116
            }
117
            this.features = null;
118
            this.lastaccess = 0;
119
        }
120
    }
121

    
122
    private static class PageCache {
123

    
124
        private final int maxpages;
125
        private List<Page> pages;
126

    
127
        public PageCache(int maxpages) {
128
            this.maxpages = maxpages;
129
            this.pages = new ArrayList<>();
130
        }
131

    
132
        public void clear() {
133
            pages.forEach((page) -> {
134
                page.dispose();
135
            });
136
            this.pages = new ArrayList<>();
137
        }
138

    
139
        public Page get(long pageNumber) {
140
            for (Page page : pages) {
141
                if (page.getPageNumber() == pageNumber) {
142
                    return page;
143
                }
144
            }
145
            return null;
146
        }
147

    
148
        public void add(Page page) {
149
            if (this.pages.size() < this.maxpages) {
150
                this.pages.add(page);
151
                return;
152
            }
153
            int toDrop = 0;
154
            for (int i = 0; i < this.pages.size(); i++) {
155
                if (this.pages.get(i).getLastAccess() < this.pages.get(toDrop).getLastAccess()) {
156
                    toDrop = i;
157
                }
158
            }
159
            this.pages.set(toDrop, page);
160
        }
161
    }
162

    
163
    private FeatureQuery query;
164

    
165
    private FeatureStore featureStore;
166

    
167
    /**
168
     * If the selected Features must be returned as the first ones. *
169
     */
170
    private boolean selectionUp = false;
171

    
172
    private FeatureSet featSet = null;
173

    
174
    private Feature[] features = null;
175
    private PageCache cachedPages = null;
176

    
177
    private boolean initialization_completed = false;
178

    
179
    private FeatureSelection selection = null;
180

    
181
    /**
182
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
183
     *
184
     * @param featureStore to extract data from
185
     * @throws DataException if there is an error initializing the helper
186
     */
187
    public FeaturePagingHelperImpl(FeatureStore featureStore)
188
            throws BaseException {
189
        this(featureStore, DEFAULT_PAGE_SIZE);
190
    }
191

    
192
    /**
193
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
194
     *
195
     * @param featureStore to extract data from
196
     * @param pageSize the number of elements per page data
197
     * @throws DataException if there is an error initializing the helper
198
     */
199
    public FeaturePagingHelperImpl(FeatureStore featureStore, int pageSize)
200
            throws BaseException {
201
        this(featureStore, null, pageSize);
202
    }
203

    
204
    /**
205
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
206
     *
207
     * @param featureStore to extract data from
208
     * @param featureQuery
209
     * @throws DataException 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
     *
219
     * @param featureStore
220
     * @param featureQuery
221
     * @param pageSize the number of elements per page data
222
     * @throws DataException if there is an error initializing the helper
223
     */
224
    public FeaturePagingHelperImpl(FeatureStore featureStore,
225
            FeatureQuery featureQuery, int pageSize) throws BaseException {
226
        super();
227
        this.cachedPages = new PageCache(3);
228
        FeatureQuery theQuery = featureQuery;
229
        if (featureQuery == null) {
230
            theQuery = featureStore.createFeatureQuery();
231
            theQuery.setFeatureType(featureStore.getDefaultFeatureType());
232
        }
233

    
234
        this.featureStore = featureStore;
235
        DisposeUtils.bind(this.featureStore);
236
        
237
        this.query = theQuery;
238
        this.query.setPageSize(pageSize);
239

    
240
        setDefaultCalculator(() -> {
241
            FeatureSet featureSet = getFeatureSet(false);
242
            try {
243
                return featureSet.getSize();
244
            } catch (BaseException e) {
245
                LOG.warn("Error getting the size of the FeatureSet: " + featureSet, e);
246
                return 0l;
247
            }
248
        }, pageSize);
249
        if (LOG.isDebugEnabled()) {
250
            LOG.debug("FeaturePagingHelperImpl created with {} pages, and a page size of {}",
251
                    getCalculator().getNumPages(), pageSize
252
            );
253
        }
254
        this.initialization_completed = true;
255
    }
256

    
257
    /**
258
     * @return the selectionUp status
259
     */
260
    @Override
261
    public boolean isSelectionUp() {
262
        return selectionUp;
263
    }
264

    
265
    @Override
266
    public FeatureSelection getSelection() {
267
        if (selection == null) {
268
            try {
269
                return getFeatureStore().getFeatureSelection();
270
            } catch (Exception e) {
271
                LOG.warn("Error getting the selection", e);
272
            }
273
        }
274
        return selection;
275
    }
276

    
277
    @Override
278
    public void setSelection(FeatureSelection selection) {
279
        this.selection = selection;
280
    }
281

    
282
    @Override
283
    public void setSelectionUp(boolean selectionUp) {
284
        this.selectionUp = selectionUp;
285
        try {
286
            this.cachedPages.clear();
287
            FeatureSelection currentSelection = getSelection();
288
            if (selectionUp && !currentSelection.isEmpty()) {
289
//                initialSelection =(FeatureSelection) currentSelection.clone();
290
                setCalculator(new OneSubsetOneSetPagingCalculator(
291
                        new FeatureSetSizeableDelegate(currentSelection),
292
                        new FeatureSetSizeableDelegate(getFeatureSet(false)),
293
                        getMaxPageSize()));
294
            } else {
295
                setDefaultCalculator(new FeatureSetSizeableDelegate(
296
                        getFeatureSet(false)), getMaxPageSize()
297
                );
298
            }
299
        } catch (BaseException e) {
300
            LOG.warn("Error setting the selection up setting to: " + selectionUp, e);
301
        }
302
    }
303

    
304
    @Override
305
    public synchronized Feature getFeatureAt(long index) throws BaseException {
306
        // Check if we have currently loaded the viewed page data,
307
        // or we need to load a new one
308
        int maxPageSize = getMaxPageSize();
309
        long currentPage = getCurrentPage();
310
        long currentPage2 = currentPage;
311

    
312
        long pageForIndex = (long) Math.floor(index / maxPageSize);
313

    
314
        if (pageForIndex != currentPage) {
315
            setCurrentPage(pageForIndex);
316
            currentPage2 = getCurrentPage();
317
        }
318

    
319
        long positionForIndex = index - (currentPage2 * maxPageSize);
320

    
321
        if (positionForIndex >= getCurrentPageFeatures().length) {
322
            throw new FeatureIndexException(
323
                    new IndexOutOfBoundsException("positionForIndex too big: "
324
                            + positionForIndex));
325
        } else {
326
            Feature feature = getCurrentPageFeatures()[(int) positionForIndex];
327
            return feature;
328
        }
329

    
330
    }
331

    
332
    @Override
333
    public Feature[] getCurrentPageFeatures() {
334
        if (this.features == null) {
335
            try {
336
                this.loadCurrentPageData();
337
            } catch (BaseException ex) {
338
                // Do nothing
339
            }
340
            if (this.features == null) {
341
                String msg = "Can't retrieve the features from current page.";
342
                LOG.warn(msg);
343
                throw new RuntimeException(msg);
344
            }
345
        }
346
        return features;
347
    }
348

    
349
    @Override
350
    public FeatureSet getFeatureSet() {
351
        return this.getFeatureSet(false);
352
    }
353

    
354
    /**
355
     * Gets the feature set. The boolean tells whether we must create the
356
     * featureset again (for example perhaps we need it after a feature has been
357
     * added/removed)
358
     */
359
    private FeatureSet getFeatureSet(boolean reset) {
360

    
361
        if (featSet == null || reset) {
362

    
363
            if (featSet != null) {
364
                try {
365
                    featSet.dispose();
366
                } catch (Exception ex) {
367
                    LOG.info("Error while disposing featset.", ex);
368
                }
369
            }
370

    
371
            try {
372
                FeatureStore featureStore = getFeatureStore();
373
                synchronized (featureStore) {
374
                    featSet = featureStore.getFeatureSet(getFeatureQuery());
375
                }
376
            } catch (DataException e) {
377
                throw new RuntimeException("Error getting a feature set with the query " + getFeatureQuery());
378
            }
379
        }
380
        return featSet;
381
    }
382

    
383
    @Override
384
    public DynObjectSet getDynObjectSet() {
385
        return getFeatureSet(false).getDynObjectSet();
386
    }
387

    
388
    @Override
389
    public void reloadCurrentPage() throws BaseException {
390
        boolean sel_up = this.isSelectionUp();
391
        try {
392
            setSelectionUp(false);
393
            if (getCalculator().getCurrentPage() > -1) {
394
                this.cachedPages.clear();
395
                loadCurrentPageData();
396
            }
397
        } finally {
398
            if (sel_up) {
399
                setSelectionUp(true);
400
            }
401
        }
402
    }
403

    
404
    @Override
405
    public void reload() throws BaseException {
406

    
407
        this.cachedPages.clear();
408
        /*
409
         * Force re-creation of feature set
410
         */
411
        this.getFeatureSet(true);
412

    
413
        setDefaultCalculator(() -> {
414
            FeatureSet featureSet = getFeatureSet(false);
415
            try {
416
                return featureSet.getSize();
417
            } catch (BaseException e) {
418
                LOG.warn("Error getting the size of the FeatureSet: "+ featureSet, e);
419
                return 0l;
420
            }
421
        }, getCalculator().getMaxPageSize());
422
//        reloadCurrentPage();
423
    }
424

    
425
    @Override
426
    public FeatureStore getFeatureStore() {
427
        return featureStore;
428
    }
429

    
430
    @Override
431
    public FeatureQuery getFeatureQuery() {
432
        return query;
433
    }
434

    
435
    /**
436
     * Loads all the Features of the current page.
437
     *
438
     * @throws org.gvsig.tools.exception.BaseException
439
     */
440
    @Override
441
    protected synchronized void loadCurrentPageData() throws BaseException {
442
        if (!initialization_completed) {
443
            return;
444
        }
445
        final int currentPageSize = getCalculator().getCurrentPageSize();
446
        final long currentPage = getCalculator().getCurrentPage();
447
        Page page = this.cachedPages.get(currentPage);
448
        if (page == null) {
449
            page = new Page(currentPage, currentPageSize);
450

    
451
            long t1 = 0;
452
            if (LOG.isTraceEnabled()) {
453
                t1 = System.currentTimeMillis();
454
            }
455

    
456
            if (selectionUp) {
457
                loadCurrentPageDataWithSelectionUp(page);
458
            } else {
459
                loadCurrentPageDataNoSelection(page);
460
            }
461

    
462
            if (LOG.isTraceEnabled()) {
463
                long t2 = System.currentTimeMillis();
464
                LOG.trace("Time to load {} features: {} ms", currentPageSize, t2 - t1);
465
            }
466
            this.cachedPages.add(page);
467
        }
468
        this.features = page.getFeatures();
469
    }
470

    
471
    private void loadCurrentPageDataWithSelectionUp(final Page page)
472
            throws BaseException {
473
        FeatureSelection theSelection = getSelection();
474
        if (theSelection == null) {
475
            loadCurrentPageDataNoSelection(page);
476
        } else {
477
            FeatureSet set = getFeatureSet(false);
478
            try {
479
                OneSubsetOneSetPagingCalculator twoSetsCalculator = null;
480
                if (getCalculator() instanceof OneSubsetOneSetPagingCalculator) {
481
                    twoSetsCalculator = (OneSubsetOneSetPagingCalculator) getCalculator();
482
                } else {
483
                    twoSetsCalculator = new OneSubsetOneSetPagingCalculator(
484
                                    new FeatureSetSizeableDelegate(theSelection),
485
                                    new FeatureSetSizeableDelegate(set),
486
                                    getMaxPageSize(), getCalculator().getCurrentPage()
487
                    );
488
                    setCalculator(twoSetsCalculator);
489
                }
490
                // First load values from the selection, if the current page has
491
                // elements from it
492
                if (twoSetsCalculator.hasCurrentPageAnyValuesInFirstSet()) {
493
                    loadDataFromFeatureSet(page, 0, theSelection,
494
                            twoSetsCalculator.getFirstSetInitialIndex(),
495
                            twoSetsCalculator.getFirstSetHowMany(), null
496
                    );
497
                }
498
                // Next, load values from the FeatureSet if the current page has values
499
                // from it
500
                if (twoSetsCalculator.hasCurrentPageAnyValuesInSecondSet()) {
501
                    loadDataFromFeatureSet(
502
                            page,
503
                            // The cast will work as that size will be <= maxpagesize,
504
                            // which is an int
505
                            (int) twoSetsCalculator.getFirstSetHowMany(), set,
506
                            twoSetsCalculator.getSecondSetInitialIndex(),
507
                            twoSetsCalculator.getSecondSetHowMany(), theSelection
508
                    );
509
                }
510
            } finally {
511
                // This is the feature set we dont want to lose it
512
                // set.dispose();
513
            }
514
        }
515
    }
516

    
517
    private void loadCurrentPageDataNoSelection(final Page page)
518
            throws BaseException {
519

    
520
        long firstPosition = getCalculator().getInitialIndex();
521

    
522
        if (LOG.isDebugEnabled()) {
523
            LOG.debug("Loading {} Features starting at position {}",
524
                    getCalculator().getCurrentPageSize(), firstPosition
525
            );
526
        }
527

    
528
        FeatureSet featureSet = getFeatureSet(false);
529
        try {
530
            loadDataFromFeatureSet(page, 0, featureSet, firstPosition,
531
                    getCalculator().getCurrentPageSize(), null);
532
        } catch (DataException ex) {
533
            throw ex;
534
        } finally {
535
            // This is the feature set we dont want to lose it
536
            // featureSet.dispose();
537
        }
538
    }
539

    
540
    private void loadDataFromFeatureSet(final Page page,
541
            final int valuesPosition, FeatureSet set, long initialIndex,
542
            final long howMany, final FeatureSelection selectedFeaturesToSkip)
543
            throws DataException {
544

    
545
        try {
546
            final MutableBoolean errorReported = new MutableBoolean(false);
547
            set.accept(new Visitor() {
548
                private int i = valuesPosition;
549

    
550
                @Override
551
                public void visit(Object obj) throws VisitCanceledException,
552
                        BaseException {
553
                    if (i >= valuesPosition + howMany) {
554
                        throw new VisitCanceledException();
555
                    }
556
                    Feature current = (Feature) obj;
557
                    // Add the current Feature only if we don't skip selected
558
                    // features or the feature is not selected
559
                    if (selectedFeaturesToSkip == null
560
                            || !selectedFeaturesToSkip.isSelected(current)) {
561
                        try {
562
                            page.setFeature(i, current.getCopy());
563
                            i++;
564
                        } catch (Exception ex) {
565
                            // Aqui no deberia petar, pero...
566
                            // me he encontrado un caso que tenia una referencia a
567
                            // una feature seleccionada que ya no existia. No se como
568
                            // habia pasado, se habia quedado de antes guardada en el
569
                            // proyecto pero la feature ya no existia, y eso hacia que
570
                            // petase al intentar leer de disco la feature a partir
571
                            // de una referencia no valida.
572
                            if (!errorReported.booleanValue()) {
573
                                // Solo sacamos un error por pagina de datos.
574
                                LOG.warn("Problemas recuperando feature.", ex);
575
                                errorReported.setTrue();
576
                            }
577
                        }
578
                    }
579
                }
580
            }, initialIndex, howMany);
581
        } catch (VisitCanceledException ex) {
582
            // Do nothing
583
        } catch (BaseException e) {
584
            if (e instanceof DataException) {
585
                throw ((DataException) e);
586
            } else {
587
                LOG.warn("Error loading the data starting at position {}", initialIndex, e);
588
            }
589
        }
590
    }
591

    
592
    @Override
593
    public void delete(Feature feature) throws BaseException {
594
        featureStore.delete(feature);
595
        /*
596
         * Force re-creation of feature set
597
         */
598
        this.getFeatureSet(true);
599

    
600
        reloadCurrentPage();
601
    }
602

    
603
    @Override
604
    public void insert(EditableFeature feature) throws BaseException {
605
        featureStore.insert(feature);
606
        /*
607
         * Force re-creation of feature set
608
         */
609
        this.getFeatureSet(true);
610

    
611
        reloadCurrentPage();
612
    }
613

    
614
    @Override
615
    public boolean isEmpty() {
616
        try {
617
            return getFeatureSet(false).isEmpty();
618
        } catch (ConcurrentDataModificationException ex) {
619
            LOG.warn("ConcurrentDataModification error asking about the emptiness of the list. Retrying reloading data.");
620
            try {
621
                reload();
622
            } catch (BaseException e) {
623
                LOG.warn("Error reloading data.", e);
624
                throw new RuntimeException(e);
625
            }
626
            try {
627
                return getFeatureSet(false).isEmpty();
628
            } catch (RuntimeException e) {
629
                throw  e;
630
            } catch (Exception e) {
631
                LOG.warn("Error asking about the emptiness of the list after reloading data.", e);
632
                throw new RuntimeException(e);
633
            }
634
        } catch (Exception ex) {
635
            throw new RuntimeException(ex);
636
        }
637
    }
638

    
639
    @Override
640
    public void update(EditableFeature feature) throws BaseException {
641
        featureStore.update(feature);
642
        /*
643
         * Force re-creation of feature set
644
         */
645
        this.getFeatureSet(true);
646

    
647
        reloadCurrentPage();
648
    }
649

    
650
    @Override
651
    public FeatureType getFeatureType() {
652

    
653
        FeatureType ft = null;
654

    
655
        try {
656
            ft = featureStore.getDefaultFeatureType();
657
        } catch (DataException e) {
658
            LOG.warn("Error while getting feature type: "+ e.getMessage(), e);
659
        }
660
        return ft;
661
    }
662

    
663
    @Override
664
    protected void doDispose() throws BaseException {
665
        if (featSet != null) {
666
            try {
667
                featSet.dispose();
668
            } catch (Exception ex) {
669
                LOG.info("Error while disposing featset.", ex);
670
            }
671
        }
672
    }
673

    
674
    @Override
675
    public DynObject[] getCurrentPageDynObjects() {
676
        Feature[] theFeatures = getCurrentPageFeatures();
677
        DynObject[] dynobjects = new DynObject[theFeatures.length];
678
        for (int i = 0; i < dynobjects.length; i++) {
679
            dynobjects[i] = new DynObjectFeatureFacade(theFeatures[i]);
680
        }
681
        return dynobjects;
682
    }
683

    
684
    @Override
685
    public DynObject getDynObjectAt(long index) throws BaseException {
686
        return new DynObjectFeatureFacade(getFeatureAt(index));
687
    }
688

    
689
    @Override
690
    public List asList() {
691
        return new FeaturePagingHelperList();
692
    }
693

    
694
    @Override
695
    public List asListOfDynObjects() {
696
        return new DynObjectPagingHelperList();
697
    }
698

    
699
    private class FeaturePagingHelperList extends PagingHelperList {
700

    
701
        @Override
702
        public Object get(int i) {
703
            return this.get64(i);
704
        }
705

    
706
        @Override
707
        public Object get64(long i) {
708
            try {
709
                return getFeatureAt(i);
710
            } catch (ConcurrentDataModificationException ex) {
711
                LOG.warn("ConcurrentDataModification error getting feature " + i + " of the list. Retrying reloading data.");
712
                try {
713
                    reload();
714
                } catch (BaseException e) {
715
                    LOG.warn("Error reloading data.", e);
716
                    throw new RuntimeException(e);
717
                }
718
                try {
719
                    return getFeatureAt(i);
720
                } catch (Exception e) {
721
                    LOG.warn("Error getting feature " + i + " of the list after reloading data.", e);
722
                    throw new RuntimeException(e);
723
                }
724
            } catch (BaseException ex) {
725
                throw new RuntimeException(ex);
726
            }
727
        }
728

    
729
        @Override
730
        public Object set(int i, Object e) {
731
            return super.set(i, e);
732
        }
733

    
734
        @Override
735
        public Object remove(int i) {
736
            return super.remove(i);
737
        }
738

    
739
        @Override
740
        public boolean add(Object e) {
741
            return super.add(e);
742
        }
743
    }
744

    
745
    private class DynObjectPagingHelperList extends PagingHelperList {
746

    
747
        @Override
748
        public Object get(int i) {
749
            return this.get64(i);
750
        }
751

    
752
        @Override
753
        public Object get64(long position) {
754
            try {
755
                return getDynObjectAt(position);
756
            } catch (ConcurrentDataModificationException ex) {
757
                LOG.warn("ConcurrentDataModification error getting element " + position + " of the list. Retrying reloading data.");
758
                try {
759
                    reload();
760
                } catch (BaseException e) {
761
                    LOG.warn("Error reloading data.", e);
762
                    throw new RuntimeException(e);
763
                }
764
                try {
765
                    return getDynObjectAt(position);
766
                } catch (Exception e) {
767
                    LOG.warn("Error getting element " + position + " of the list after reloading data.", e);
768
                    throw new RuntimeException(e);
769
                }
770
            } catch (BaseException ex) {
771
                throw new RuntimeException(ex);
772
            }
773
        }
774

    
775
    }
776

    
777
    private abstract class PagingHelperList implements List, FacadeOfAFeaturePagingHelper, UnmodifiableBasicList, UnmodifiableBasicList64, Disposable {
778

    
779
        @Override
780
        public void dispose() {
781
            FeaturePagingHelperImpl.this.dispose();
782
        }
783

    
784
        @Override
785
        public FeaturePagingHelper getFeaturePagingHelper() {
786
            return FeaturePagingHelperImpl.this;
787
        }
788

    
789
        @Override
790
        public String toString() {
791
            return String.format("..(%d %ss)...", this.size(), featureStore.getName());
792
        }
793

    
794
        @Override
795
        public long size64() {
796
            FeatureSet fset = null;
797
            try {
798
                fset = getFeatureSet(false);
799
                return fset.getSize();
800
            } catch (ConcurrentDataModificationException ex) {
801
                LOG.warn("ConcurrentDataModification error asking the size of the list. Retrying reloading data.");
802
                try {
803
                    reload();
804
                } catch (BaseException e) {
805
                    LOG.warn("Error reloading data.", e);
806
                    throw new RuntimeException(e);
807
                }
808
                try {
809
                    fset = getFeatureSet(false);
810
                    return fset.getSize();
811
                } catch (DataException e) {
812
                    LOG.warn("Error asking the size of the list after reloading data.", e);
813
                    throw new RuntimeException(e);
814
                }
815
            } catch (DataException ex) {
816
                throw new RuntimeException(ex);
817
            }
818
        }
819

    
820
        @Override
821
        public int size() {
822
            long sz = this.size64();
823
            if (sz > Integer.MAX_VALUE) {
824
                sz = Integer.MAX_VALUE;
825
            }
826
            return (int) sz;
827
        }
828

    
829
        @Override
830
        public boolean isEmpty() {
831
            try {
832
                return getFeatureSet(false).isEmpty();
833
            } catch (ConcurrentDataModificationException ex) {
834
                LOG.warn("ConcurrentDataModification error asking about the emptiness of the list. Retrying reloading data.");
835
                try {
836
                    reload();
837
                } catch (BaseException e) {
838
                    LOG.warn("Error reloading data.", e);
839
                    throw new RuntimeException(e);
840
                }
841
                try {
842
                    return getFeatureSet(false).isEmpty();
843
                } catch (RuntimeException e) {
844
                    throw  e;
845
                } catch (Exception e) {
846
                    LOG.warn("Error asking about the emptiness of the list after reloading data.", e);
847
                    throw new RuntimeException(e);
848
                }
849
            } catch (RuntimeException ex) {
850
                throw  ex;
851
            } catch (Exception ex) {
852
                throw new RuntimeException(ex);
853
            }
854
        }
855

    
856
        @Override
857
        public Iterator iterator() {
858
            try {
859
                return getFeatureSet(false).fastIterator();
860
            } catch (ConcurrentDataModificationException ex) {
861
                LOG.warn("ConcurrentDataModification error getting iterator of the list. Retrying reloading data.");
862
                try {
863
                    reload();
864
                } catch (BaseException e) {
865
                    LOG.warn("Error reloading data.", e);
866
                    throw new RuntimeException(e);
867
                }
868
                try {
869
                    return getFeatureSet(false).fastIterator();
870
                } catch (DataException e) {
871
                    LOG.warn("Error getting iterator of the list after reloading data.", e);
872
                    throw new RuntimeException(e);
873
                }
874
            } catch (DataException ex) {
875
                throw new RuntimeException(ex);
876
            }
877
        }
878

    
879
        @Override
880
        public boolean contains(Object o) {
881
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
882
        }
883

    
884
        @Override
885
        public Object[] toArray() {
886
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
887
        }
888

    
889
        @Override
890
        public Object[] toArray(Object[] ts) {
891
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
892
        }
893

    
894
        @Override
895
        public boolean add(Object e) {
896
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
897
        }
898

    
899
        @Override
900
        public boolean remove(Object o) {
901
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
902
        }
903

    
904
        @Override
905
        public boolean containsAll(Collection clctn) {
906
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
907
        }
908

    
909
        @Override
910
        public boolean addAll(Collection clctn) {
911
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
912
        }
913

    
914
        @Override
915
        public boolean addAll(int i, Collection clctn) {
916
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
917
        }
918

    
919
        @Override
920
        public boolean removeAll(Collection clctn) {
921
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
922
        }
923

    
924
        @Override
925
        public boolean retainAll(Collection clctn) {
926
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
927
        }
928

    
929
        @Override
930
        public void clear() {
931
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
932
        }
933

    
934
        @Override
935
        public Object set(int i, Object e) {
936
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
937
        }
938

    
939
        @Override
940
        public void add(int i, Object e) {
941
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
942
        }
943

    
944
        @Override
945
        public Object remove(int i) {
946
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
947
        }
948

    
949
        @Override
950
        public int indexOf(Object o) {
951
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
952
        }
953

    
954
        @Override
955
        public int lastIndexOf(Object o) {
956
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
957
        }
958

    
959
        @Override
960
        public ListIterator listIterator() {
961
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
962
        }
963

    
964
        @Override
965
        public ListIterator listIterator(int i) {
966
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
967
        }
968

    
969
        @Override
970
        public List subList(int i, int i1) {
971
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
972
        }
973

    
974
        @Override
975
        public List toList() {
976
            return this;
977
        }
978

    
979
    }
980

    
981
    @Override
982
    public long size64() {
983
        return this.getTotalSize();
984
    }
985

    
986
    @Override
987
    public Feature get64(long position) {
988
        try {
989
            return this.getFeatureAt(position);
990
        } catch (BaseException ex) {
991
            throw new RuntimeException(ex);
992
        }
993
    }
994

    
995
    @Override
996
    public Iterator<Feature> iterator() {
997
        try {
998
            return getFeatureSet(false).fastIterator();
999
        } catch (Exception ex) {
1000
            throw new RuntimeException(ex);
1001
        }
1002
    }
1003

    
1004
}