Statistics
| Revision:

svn-gvsig-desktop / branches / org.gvsig.desktop-cvsgis1 / 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 @ 45288

History | View | Annotate | Download (33.9 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.dynobject.DynObject;
52
import org.gvsig.tools.dynobject.DynObjectSet;
53
import org.gvsig.tools.dynobject.impl.DefaultDynObjectPagingHelper;
54
import org.gvsig.tools.exception.BaseException;
55
import org.gvsig.tools.util.UnmodifiableBasicList;
56
import org.gvsig.tools.util.UnmodifiableBasicList64;
57
import org.gvsig.tools.visitor.VisitCanceledException;
58
import org.gvsig.tools.visitor.Visitor;
59

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

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

    
77
    private static class Page {
78

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

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

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

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

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

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

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

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

    
121
    private static class PageCache {
122

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

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

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

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

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

    
162
    private FeatureQuery query;
163

    
164
    private FeatureStore featureStore;
165

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

    
171
    private FeatureSet featSet = null;
172

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

    
176
    private boolean initialization_completed = false;
177

    
178
    private FeatureSelection selection = null;
179

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

    
191
    /**
192
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
193
     *
194
     * @param featureStore to extract data from
195
     * @param pageSize the number of elements per page data
196
     * @throws DataException 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
     *
206
     * @param featureStore to extract data from
207
     * @param featureQuery
208
     * @throws DataException if there is an error initializing the helper
209
     */
210
    public FeaturePagingHelperImpl(FeatureStore featureStore,
211
            FeatureQuery featureQuery) throws BaseException {
212
        this(featureStore, featureQuery, DEFAULT_PAGE_SIZE);
213
    }
214

    
215
    /**
216
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
217
     *
218
     * @param featureStore
219
     * @param featureQuery
220
     * @param pageSize the number of elements per page data
221
     * @throws DataException if there is an error initializing the helper
222
     */
223
    public FeaturePagingHelperImpl(FeatureStore featureStore,
224
            FeatureQuery featureQuery, int pageSize) throws BaseException {
225
        super();
226
        this.cachedPages = new PageCache(3);
227
        FeatureQuery theQuery = featureQuery;
228
        if (featureQuery == null) {
229
            theQuery = featureStore.createFeatureQuery();
230
            theQuery.setFeatureType(featureStore.getDefaultFeatureType());
231
        }
232

    
233
        this.featureStore = featureStore;
234
        this.query = theQuery;
235
        this.query.setPageSize(pageSize);
236

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

    
254
    /**
255
     * @return the selectionUp status
256
     */
257
    @Override
258
    public boolean isSelectionUp() {
259
        return selectionUp;
260
    }
261

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

    
274
    @Override
275
    public void setSelection(FeatureSelection selection) {
276
        this.selection = selection;
277
    }
278

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

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

    
309
        long pageForIndex = (long) Math.floor(index / maxPageSize);
310

    
311
        if (pageForIndex != currentPage) {
312
            setCurrentPage(pageForIndex);
313
            currentPage2 = getCurrentPage();
314
        }
315

    
316
        long positionForIndex = index - (currentPage2 * maxPageSize);
317

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

    
327
    }
328

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

    
346
    @Override
347
    public FeatureSet getFeatureSet() {
348
        return this.getFeatureSet(false);
349
    }
350

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

    
358
        if (featSet == null || reset) {
359

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

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

    
380
    @Override
381
    public DynObjectSet getDynObjectSet() {
382
        return getFeatureSet(false).getDynObjectSet();
383
    }
384

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

    
401
    @Override
402
    public void reload() throws BaseException {
403

    
404
        this.cachedPages.clear();
405
        /*
406
         * Force re-creation of feature set
407
         */
408
        this.getFeatureSet(true);
409

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

    
422
    @Override
423
    public FeatureStore getFeatureStore() {
424
        return featureStore;
425
    }
426

    
427
    @Override
428
    public FeatureQuery getFeatureQuery() {
429
        return query;
430
    }
431

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

    
448
            long t1 = 0;
449
            if (LOG.isTraceEnabled()) {
450
                t1 = System.currentTimeMillis();
451
            }
452

    
453
            if (selectionUp) {
454
                loadCurrentPageDataWithSelectionUp(page);
455
            } else {
456
                loadCurrentPageDataNoSelection(page);
457
            }
458

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

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

    
514
    private void loadCurrentPageDataNoSelection(final Page page)
515
            throws BaseException {
516

    
517
        long firstPosition = getCalculator().getInitialIndex();
518

    
519
        if (LOG.isDebugEnabled()) {
520
            LOG.debug("Loading {} Features starting at position {}",
521
                    getCalculator().getCurrentPageSize(), firstPosition
522
            );
523
        }
524

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

    
537
    private void loadDataFromFeatureSet(final Page page,
538
            final int valuesPosition, FeatureSet set, long initialIndex,
539
            final long howMany, final FeatureSelection selectedFeaturesToSkip)
540
            throws DataException {
541

    
542
        try {
543
            final MutableBoolean errorReported = new MutableBoolean(false);
544
            set.accept(new Visitor() {
545
                private int i = valuesPosition;
546

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

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

    
597
        reloadCurrentPage();
598
    }
599

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

    
608
        reloadCurrentPage();
609
    }
610

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

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

    
644
        reloadCurrentPage();
645
    }
646

    
647
    @Override
648
    public FeatureType getFeatureType() {
649

    
650
        FeatureType ft = null;
651

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

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

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

    
681
    @Override
682
    public DynObject getDynObjectAt(long index) throws BaseException {
683
        return new DynObjectFeatureFacade(getFeatureAt(index));
684
    }
685

    
686
    @Override
687
    public List asList() {
688
        return new FeaturePagingHelperList();
689
    }
690

    
691
    @Override
692
    public List asListOfDynObjects() {
693
        return new DynObjectPagingHelperList();
694
    }
695

    
696
    private class FeaturePagingHelperList extends PagingHelperList {
697

    
698
        @Override
699
        public Object get(int i) {
700
            return this.get64(i);
701
        }
702

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

    
726
        @Override
727
        public Object set(int i, Object e) {
728
            return super.set(i, e);
729
        }
730

    
731
        @Override
732
        public Object remove(int i) {
733
            return super.remove(i);
734
        }
735

    
736
        @Override
737
        public boolean add(Object e) {
738
            return super.add(e);
739
        }
740
    }
741

    
742
    private class DynObjectPagingHelperList extends PagingHelperList {
743

    
744
        @Override
745
        public Object get(int i) {
746
            return this.get64(i);
747
        }
748

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

    
772
    }
773

    
774
    private abstract class PagingHelperList implements List, FacadeOfAFeaturePagingHelper, UnmodifiableBasicList, UnmodifiableBasicList64, Disposable {
775

    
776
        @Override
777
        public void dispose() {
778
            FeaturePagingHelperImpl.this.dispose();
779
        }
780

    
781
        @Override
782
        public FeaturePagingHelper getFeaturePagingHelper() {
783
            return FeaturePagingHelperImpl.this;
784
        }
785

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
971
        @Override
972
        public List toList() {
973
            return this;
974
        }
975

    
976
    }
977

    
978
    @Override
979
    public long size64() {
980
        return this.getTotalSize();
981
    }
982

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

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

    
1001
}