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

History | View | Annotate | Download (33 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 org.apache.commons.lang3.mutable.MutableBoolean;
33
import org.slf4j.Logger;
34
import org.slf4j.LoggerFactory;
35

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

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

    
73
    private static final Logger LOG = LoggerFactory.getLogger(FeaturePagingHelperImpl.class);
74

    
75
    private static class Page {
76

    
77
        private Feature[] features;
78
        private final long number;
79
        private final int size;
80
        private long lastaccess;
81

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

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

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

    
98
        public long getPageNumber() {
99
            return this.number;
100
        }
101

    
102
        public long getLastAccess() {
103
            return this.lastaccess;
104
        }
105

    
106
        public int size() {
107
            return this.size;
108
        }
109

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

    
119
    private static class PageCache {
120

    
121
        private final int maxpages;
122
        private List<Page> pages;
123

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

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

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

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

    
160
    private FeatureQuery query;
161

    
162
    private FeatureStore featureStore;
163

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

    
169
    private FeatureSet featSet = null;
170

    
171
    private Feature[] features = null;
172
    private PageCache cachedPages = null;
173

    
174
    private boolean initialization_completed = false;
175

    
176
    private FeatureSelection selection = null;
177

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

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

    
201
    /**
202
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
203
     *
204
     * @param featureStore to extract data from
205
     * @param featureQuery
206
     * @throws DataException if there is an error initializing the helper
207
     */
208
    public FeaturePagingHelperImpl(FeatureStore featureStore,
209
            FeatureQuery featureQuery) throws BaseException {
210
        this(featureStore, featureQuery, DEFAULT_PAGE_SIZE);
211
    }
212

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

    
231
        this.featureStore = featureStore;
232
        this.query = theQuery;
233
        this.query.setPageSize(pageSize);
234

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

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

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

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

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

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

    
307
        long pageForIndex = (long) Math.floor(index / maxPageSize);
308

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

    
314
        long positionForIndex = index - (currentPage2 * maxPageSize);
315

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

    
325
    }
326

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

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

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

    
356
        if (featSet == null || reset) {
357

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

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

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

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

    
399
    @Override
400
    public void reload() throws BaseException {
401

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

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

    
420
    @Override
421
    public FeatureStore getFeatureStore() {
422
        return featureStore;
423
    }
424

    
425
    @Override
426
    public FeatureQuery getFeatureQuery() {
427
        return query;
428
    }
429

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

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

    
451
            if (selectionUp) {
452
                loadCurrentPageDataWithSelectionUp(page);
453
            } else {
454
                loadCurrentPageDataNoSelection(page);
455
            }
456

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

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

    
512
    private void loadCurrentPageDataNoSelection(final Page page)
513
            throws BaseException {
514

    
515
        long firstPosition = getCalculator().getInitialIndex();
516

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

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

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

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

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

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

    
595
        reloadCurrentPage();
596
    }
597

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

    
606
        reloadCurrentPage();
607
    }
608

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

    
632
    @Override
633
    public void update(EditableFeature feature) throws BaseException {
634
        featureStore.update(feature);
635
        /*
636
         * Force re-creation of feature set
637
         */
638
        this.getFeatureSet(true);
639

    
640
        reloadCurrentPage();
641
    }
642

    
643
    @Override
644
    public FeatureType getFeatureType() {
645

    
646
        FeatureType ft = null;
647

    
648
        try {
649
            ft = featureStore.getDefaultFeatureType();
650
        } catch (DataException e) {
651
            LOG.warn("Error while getting feature type: "+ e.getMessage(), e);
652
        }
653
        return ft;
654
    }
655

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

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

    
677
    @Override
678
    public DynObject getDynObjectAt(long index) throws BaseException {
679
        return new DynObjectFeatureFacade(getFeatureAt(index));
680
    }
681

    
682
    @Override
683
    public List asList() {
684
        return new FeaturePagingHelperList();
685
    }
686

    
687
    @Override
688
    public List asListOfDynObjects() {
689
        return new DynObjectPagingHelperList();
690
    }
691

    
692
    private class FeaturePagingHelperList extends PagingHelperList {
693

    
694
        @Override
695
        public Object get(int i) {
696
            return this.get64(i);
697
        }
698

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

    
722
        @Override
723
        public Object set(int i, Object e) {
724
            return super.set(i, e);
725
        }
726

    
727
        @Override
728
        public Object remove(int i) {
729
            return super.remove(i);
730
        }
731

    
732
        @Override
733
        public boolean add(Object e) {
734
            return super.add(e);
735
        }
736
    }
737

    
738
    private class DynObjectPagingHelperList extends PagingHelperList {
739

    
740
        @Override
741
        public Object get(int i) {
742
            return this.get64(i);
743
        }
744

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

    
768
    }
769

    
770
    private abstract class PagingHelperList implements List, FacadeOfAFeaturePagingHelper, UnmodifiableBasicList, UnmodifiableBasicList64 {
771

    
772
        @Override
773
        public FeaturePagingHelper getFeaturePagingHelper() {
774
            return FeaturePagingHelperImpl.this;
775
        }
776

    
777
        @Override
778
        public String toString() {
779
            return String.format("..(%d %ss)...", this.size(), featureStore.getName());
780
        }
781

    
782
        @Override
783
        public long size64() {
784
            FeatureSet fset = null;
785
            try {
786
                fset = getFeatureSet(false);
787
                return fset.getSize();
788
            } catch (ConcurrentDataModificationException ex) {
789
                LOG.warn("ConcurrentDataModification error asking the size of the list. Retrying reloading data.");
790
                try {
791
                    reload();
792
                } catch (BaseException e) {
793
                    LOG.warn("Error reloading data.", e);
794
                    throw new RuntimeException(e);
795
                }
796
                try {
797
                    fset = getFeatureSet(false);
798
                    return fset.getSize();
799
                } catch (DataException e) {
800
                    LOG.warn("Error asking the size of the list after reloading data.", e);
801
                    throw new RuntimeException(e);
802
                }
803
            } catch (DataException ex) {
804
                throw new RuntimeException(ex);
805
            }
806
        }
807

    
808
        @Override
809
        public int size() {
810
            long sz = this.size64();
811
            if (sz > Integer.MAX_VALUE) {
812
                sz = Integer.MAX_VALUE;
813
            }
814
            return (int) sz;
815
        }
816

    
817
        @Override
818
        public boolean isEmpty() {
819
            try {
820
                return getFeatureSet(false).isEmpty();
821
            } catch (ConcurrentDataModificationException ex) {
822
                LOG.warn("ConcurrentDataModification error asking about the emptiness of the list. Retrying reloading data.");
823
                try {
824
                    reload();
825
                } catch (BaseException e) {
826
                    LOG.warn("Error reloading data.", e);
827
                    throw new RuntimeException(e);
828
                }
829
                try {
830
                    return getFeatureSet(false).isEmpty();
831
                } catch (DataException e) {
832
                    LOG.warn("Error asking about the emptiness of the list after reloading data.", e);
833
                    throw new RuntimeException(e);
834
                }
835
            } catch (DataException ex) {
836
                throw new RuntimeException(ex);
837
            }
838
        }
839

    
840
        @Override
841
        public Iterator iterator() {
842
            try {
843
                return getFeatureSet(false).fastIterator();
844
            } catch (ConcurrentDataModificationException ex) {
845
                LOG.warn("ConcurrentDataModification error getting iterator of the list. Retrying reloading data.");
846
                try {
847
                    reload();
848
                } catch (BaseException e) {
849
                    LOG.warn("Error reloading data.", e);
850
                    throw new RuntimeException(e);
851
                }
852
                try {
853
                    return getFeatureSet(false).fastIterator();
854
                } catch (DataException e) {
855
                    LOG.warn("Error getting iterator of the list after reloading data.", e);
856
                    throw new RuntimeException(e);
857
                }
858
            } catch (DataException ex) {
859
                throw new RuntimeException(ex);
860
            }
861
        }
862

    
863
        @Override
864
        public boolean contains(Object o) {
865
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
866
        }
867

    
868
        @Override
869
        public Object[] toArray() {
870
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
871
        }
872

    
873
        @Override
874
        public Object[] toArray(Object[] ts) {
875
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
876
        }
877

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

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

    
888
        @Override
889
        public boolean containsAll(Collection clctn) {
890
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
891
        }
892

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

    
898
        @Override
899
        public boolean addAll(int i, Collection clctn) {
900
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
901
        }
902

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

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

    
913
        @Override
914
        public void clear() {
915
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
916
        }
917

    
918
        @Override
919
        public Object set(int i, Object e) {
920
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
921
        }
922

    
923
        @Override
924
        public void add(int i, Object e) {
925
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
926
        }
927

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

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

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

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

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

    
953
        @Override
954
        public List subList(int i, int i1) {
955
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
956
        }
957

    
958
        @Override
959
        public List toList() {
960
            return this;
961
        }
962

    
963
    }
964
}