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

History | View | Annotate | Download (36.4 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
        DisposeUtils.disposeQuietly(this.selection);
280
        this.selection = selection;
281
        DisposeUtils.bind(this.selection);
282
    }
283

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

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

    
314
        long pageForIndex = (long) Math.floor(index / maxPageSize);
315

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

    
321
        long positionForIndex = index - (currentPage2 * maxPageSize);
322

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

    
332
    }
333

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

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

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

    
363
        if (featSet == null || reset) {
364

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

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

    
386
    @Override
387
    public DynObjectSet getDynObjectSet() {
388
        return getFeatureSet(false).getDynObjectSet();
389
    }
390

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

    
407
    @Override
408
    public void reload() throws BaseException {
409

    
410
        this.cachedPages.clear();
411
        /*
412
         * Force re-creation of feature set
413
         */
414
        this.getFeatureSet(true);
415

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

    
428
    @Override
429
    public FeatureStore getFeatureStore() {
430
        return featureStore;
431
    }
432

    
433
    @Override
434
    public FeatureQuery getFeatureQuery() {
435
        return query;
436
    }
437

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

    
454
            long t1 = 0;
455
            if (LOG.isTraceEnabled()) {
456
                t1 = System.currentTimeMillis();
457
            }
458

    
459
            if (selectionUp) {
460
                loadCurrentPageDataWithSelectionUp(page);
461
            } else {
462
                loadCurrentPageDataNoSelection(page);
463
            }
464

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

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

    
520
    private void loadCurrentPageDataNoSelection(final Page page)
521
            throws BaseException {
522

    
523
        long firstPosition = getCalculator().getInitialIndex();
524

    
525
        if (LOG.isDebugEnabled()) {
526
            LOG.debug("Loading {} Features starting at position {}",
527
                    getCalculator().getCurrentPageSize(), firstPosition
528
            );
529
        }
530

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

    
543
    private void loadDataFromFeatureSet(final Page page,
544
            final int valuesPosition, FeatureSet set, long initialIndex,
545
            final long howMany, final FeatureSelection selectedFeaturesToSkip)
546
            throws DataException {
547

    
548
        try {
549
            final MutableBoolean errorReported = new MutableBoolean(false);
550
            set.accept(new Visitor() {
551
                private int i = valuesPosition;
552

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

    
597
    @Override
598
    public void delete(Feature feature) throws BaseException {
599
        featureStore.delete(feature);
600
        /*
601
         * Force re-creation of feature set
602
         */
603
        this.getFeatureSet(true);
604

    
605
        reloadCurrentPage();
606
    }
607

    
608
    @Override
609
    public void insert(EditableFeature feature) throws BaseException {
610
        featureStore.insert(feature);
611
        /*
612
         * Force re-creation of feature set
613
         */
614
        this.getFeatureSet(true);
615

    
616
        reloadCurrentPage();
617
    }
618

    
619
    @Override
620
    public boolean isEmpty() {
621
        try {
622
            return getFeatureSet(false).isEmpty();
623
        } catch (ConcurrentDataModificationException ex) {
624
            LOG.warn("ConcurrentDataModification error asking about the emptiness of the list. Retrying reloading data. "+(featSet==null?0:featSet.hashCode()));
625
            try {
626
                reload();
627
            } catch (BaseException e) {
628
                LOG.warn("Error reloading data. "+(featSet==null?0:featSet.hashCode()), e);
629
                throw new RuntimeException(e);
630
            }
631
            try {
632
                return getFeatureSet(false).isEmpty();
633
            } catch (RuntimeException e) {
634
                throw  e;
635
            } catch (Exception e) {
636
                LOG.warn("Error asking about the emptiness of the list after reloading data. "+(featSet==null?0:featSet.hashCode()), e);
637
                throw new RuntimeException(e);
638
            }
639
        } catch (Exception ex) {
640
            throw new RuntimeException(ex);
641
        }
642
    }
643

    
644
    @Override
645
    public void update(EditableFeature feature) throws BaseException {
646
        featureStore.update(feature);
647
        /*
648
         * Force re-creation of feature set
649
         */
650
        this.getFeatureSet(true);
651

    
652
        reloadCurrentPage();
653
    }
654

    
655
    @Override
656
    public FeatureType getFeatureType() {
657

    
658
        FeatureType ft = null;
659

    
660
        try {
661
            ft = featureStore.getDefaultFeatureType();
662
        } catch (DataException e) {
663
            LOG.warn("Error while getting feature type: "+ e.getMessage(), e);
664
        }
665
        return ft;
666
    }
667

    
668
    @Override
669
    protected void doDispose() throws BaseException {
670
        DisposeUtils.disposeQuietly(this.featSet);
671
        DisposeUtils.disposeQuietly(this.featureStore);
672
        DisposeUtils.disposeQuietly(this.selection);
673
    }
674

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

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

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

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

    
700
    private class FeaturePagingHelperList extends PagingHelperList {
701

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

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

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

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

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

    
746
    private class DynObjectPagingHelperList extends PagingHelperList {
747

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

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

    
776
    }
777

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
980
    }
981

    
982
    @Override
983
    public long size64() {
984
        try {
985
            return this.getTotalSize();
986
        } catch (ConcurrentDataModificationException ex) {
987
            LOG.warn("ConcurrentDataModification error getting size of the list. Retrying reloading data. "+(featSet==null?0:featSet.hashCode()));
988
            try {
989
                reload();
990
            } catch (BaseException e) {
991
                LOG.warn("Error reloading data. "+(featSet==null?0:featSet.hashCode()), e);
992
                throw new RuntimeException(e);
993
            }
994
            try {
995
                return this.getTotalSize();
996
            } catch (Exception e) {
997
                LOG.warn("Error getting size of the list after reloading data. "+(featSet==null?0:featSet.hashCode()), e);
998
                throw new RuntimeException(e);
999
            }
1000
        } catch (Exception ex) {
1001
            throw new RuntimeException(ex);
1002
        }
1003
    }
1004

    
1005
    @Override
1006
    public Feature get64(long position) {
1007
        try {
1008
            return getFeatureAt(position);
1009
        } catch (ConcurrentDataModificationException ex) {
1010
            LOG.warn("ConcurrentDataModification error getting element " + position + " of the list. Retrying reloading data. "+(featSet==null?0:featSet.hashCode()));
1011
            try {
1012
                reload();
1013
            } catch (BaseException e) {
1014
                LOG.warn("Error reloading data. "+(featSet==null?0:featSet.hashCode()), e);
1015
                throw new RuntimeException(e);
1016
            }
1017
            try {
1018
                return getFeatureAt(position);
1019
            } catch (Exception e) {
1020
                LOG.warn("Error getting element " + position + " of the list after reloading data. "+(featSet==null?0:featSet.hashCode()), e);
1021
                throw new RuntimeException(e);
1022
            }
1023
        } catch (BaseException ex) {
1024
            throw new RuntimeException(ex);
1025
        }
1026
    }
1027

    
1028
    @Override
1029
    public Iterator<Feature> iterator() {
1030
        try {
1031
            return getFeatureSet(false).fastIterator();
1032
        } catch (Exception ex) {
1033
            throw new RuntimeException(ex);
1034
        }
1035
    }
1036

    
1037
}