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

History | View | Annotate | Download (34 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 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.dynobject.DynObject;
51
import org.gvsig.tools.dynobject.DynObjectSet;
52
import org.gvsig.tools.dynobject.impl.DefaultDynObjectPagingHelper;
53
import org.gvsig.tools.exception.BaseException;
54
import org.gvsig.tools.util.UnmodifiableBasicList;
55
import org.gvsig.tools.util.UnmodifiableBasicList64;
56
import org.gvsig.tools.visitor.VisitCanceledException;
57
import org.gvsig.tools.visitor.Visitor;
58

    
59
/**
60
 * Helper class to access the values of a FeatureCollection by position. Handles
61
 * pagination automatically to avoid filling the memory in case of big
62
 * collections.
63
 *
64
 * TODO: evaluate if its more convenient to read values in the background when
65
 * the returned value is near the end of the page, instead of loading a page on
66
 * demand.
67
 *
68
 * @author gvSIG Team
69
 */
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
            for (Page page : pages) {
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
    /** If the selected Features must be returned as the first ones. **/
165
    private boolean selectionUp = false;
166

    
167
    private FeatureSet featSet = null;
168
    private FeatureSelection initialSelection = null;
169

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

    
173
    private boolean initialization_completed = false;
174

    
175
    private FeatureSelection selection = null;
176
    /**
177
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
178
     *
179
     * @param featureStore
180
     *            to extract data from
181
     * @throws DataException
182
     *             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
193
     *            to extract data from
194
     * @param pageSize
195
     *            the number of elements per page data
196
     * @throws DataException
197
     *             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
208
     *            to extract data from
209
     * @throws DataException
210
     *             if there is an error initializing the helper
211
     */
212
    public FeaturePagingHelperImpl(FeatureStore featureStore,
213
        FeatureQuery featureQuery) throws BaseException {
214
        this(featureStore, featureQuery, DEFAULT_PAGE_SIZE);
215
    }
216

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

    
237
        this.featureStore = featureStore;
238
        this.query = query;
239
        this.query.setPageSize(pageSize);
240

    
241
        setDefaultCalculator(new Sizeable() {
242
            public long getSize() {
243
                    FeatureSet featureSet = getFeatureSet(false);
244
                try {
245
                                        return featureSet.getSize();
246
                } catch (BaseException e) {
247
                    LOG.error("Error getting the size of the FeatureSet: "
248
                        + featureSet, e);
249
                    return 0l;
250
                }
251
            }
252
        }, pageSize);
253

    
254

    
255
        if (LOG.isDebugEnabled()) {
256

    
257
            LOG.debug("FeaturePagingHelperImpl created with {} pages, "
258
                + "and a page size of {}", new Long(getCalculator()
259
                .getNumPages()), new Integer(pageSize));
260
        }
261
        this.initialization_completed = true;
262
    }
263

    
264
    /**
265
     * @return the selectionUp status
266
     */
267
    public boolean isSelectionUp() {
268
        return selectionUp;
269
    }
270
    
271
    public FeatureSelection getSelection() {
272
        if (selection == null) {
273
            try {
274
                return getFeatureStore().getFeatureSelection();
275
            } catch (Exception e) {
276
                LOG.warn("Error getting the selection", e);
277
            }
278
        }
279
        return selection;
280
    }
281
    
282
    public void setSelection(FeatureSelection selection) {
283
        this.selection = selection;
284
    }
285
    
286
    @Override
287
    public void setSelectionUp(boolean selectionUp) {
288
        this.selectionUp = selectionUp;
289
        try {
290
            this.cachedPages.clear();
291
            FeatureSelection currentSelection = getSelection();
292
            if (selectionUp && !currentSelection.isEmpty()) {
293
                initialSelection =(FeatureSelection) currentSelection.clone();
294
                setCalculator(new OneSubsetOneSetPagingCalculator(
295
                    new FeatureSetSizeableDelegate(initialSelection),
296
                    new FeatureSetSizeableDelegate(getFeatureSet(false)),
297
                    getMaxPageSize()));
298
            } else {
299
                if (initialSelection != null) {
300
                    initialSelection.dispose();
301
                    initialSelection = null;
302
                }
303
                setDefaultCalculator(new FeatureSetSizeableDelegate(
304
                    getFeatureSet(false)), getMaxPageSize());
305
            }
306
        } catch (BaseException e) {
307
            LOG.error("Error setting the selection up setting to: "
308
                + selectionUp, e);
309
        } catch (CloneNotSupportedException e) {
310
            LOG.error("Error cloning the selection "
311
                + "while setting the selection up", e);
312
        }
313
    }
314

    
315
    public synchronized Feature getFeatureAt(long index) throws BaseException {
316
        // Check if we have currently loaded the viewed page data,
317
        // or we need to load a new one
318
            int maxPageSize = getMaxPageSize();
319
            long currentPage = getCurrentPage();
320
            long currentPage2 = currentPage;
321
            
322
            
323
        long pageForIndex = (long) Math.floor(index / maxPageSize);
324

    
325
        if (pageForIndex != currentPage) {
326
            setCurrentPage(pageForIndex);
327
            currentPage2 = getCurrentPage();
328
        }
329

    
330
        long positionForIndex = index - (currentPage2 * maxPageSize);
331

    
332
        if (positionForIndex >= getCurrentPageFeatures().length) {
333
            throw new FeatureIndexException(
334
                new IndexOutOfBoundsException("positionForIndex too big: "
335
                    + positionForIndex));
336
        } else {
337
            Feature feature = getCurrentPageFeatures()[(int) positionForIndex];
338
            return feature;
339
        }
340

    
341
    }
342

    
343
    public Feature[] getCurrentPageFeatures() {
344
        if( this.features==null ) {
345
            try {
346
                this.loadCurrentPageData();
347
            } catch (BaseException ex) {
348
                // Do nothing
349
            }
350
            if( this.features == null ) {
351
                String msg = "Can't retrieve the features from current page.";
352
                LOG.warn(msg);
353
                throw new RuntimeException(msg);
354
            }
355
        }
356
        return features;
357
    }
358
    
359
    @Override
360
    public FeatureSet getFeatureSet() {
361
        return this.getFeatureSet(false);
362
    }
363

    
364
    /**
365
     * Gets the feature set.
366
     * The boolean tells whether we must create the featureset
367
     * again (for example perhaps we need it after a feature
368
     * has been added/removed)
369
     */
370
    private FeatureSet getFeatureSet(boolean reset) {
371

    
372
        if (featSet == null || reset) {
373

    
374
            if (featSet != null) {
375
                try {
376
                    featSet.dispose();
377
                } catch (Exception ex) {
378
                    LOG.info("Error while disposing featset.", ex);
379
                }
380
            }
381

    
382
            try {
383
                FeatureStore featureStore = getFeatureStore();
384
                synchronized (featureStore) {
385
                    featSet = featureStore.getFeatureSet(getFeatureQuery());
386
                }
387
            } catch (DataException e) {
388
                throw new RuntimeException("Error getting a feature set with the query " + getFeatureQuery());
389
            }
390
        }
391
        return featSet;
392
    }
393

    
394
    @Override
395
    public DynObjectSet getDynObjectSet() {
396
            return getFeatureSet(false).getDynObjectSet();
397
    }
398

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

    
402
        boolean sel_up = this.isSelectionUp();
403

    
404
        setSelectionUp(false);
405
        if (getCalculator().getCurrentPage() > -1) {
406
            this.cachedPages.clear();
407
            loadCurrentPageData();
408
        }
409

    
410
        if (sel_up) {
411
            setSelectionUp(true);
412
        }
413
    }
414

    
415
    @Override
416
    public void reload() throws BaseException {
417

    
418
        this.cachedPages.clear();
419
        /*
420
         * Force re-creation of feature set
421
         */
422
        this.getFeatureSet(true);
423

    
424

    
425
        setDefaultCalculator(new Sizeable() {
426
            public long getSize() {
427
                    FeatureSet featureSet = getFeatureSet(false);
428
                try {
429
                                        return featureSet.getSize();
430
                } catch (BaseException e) {
431
                    LOG.error("Error getting the size of the FeatureSet: "
432
                        + featureSet, e);
433
                    return 0l;
434
                }
435
            }
436
        }, getCalculator().getMaxPageSize());
437
        reloadCurrentPage();
438
    }
439

    
440
    public FeatureStore getFeatureStore() {
441
        return featureStore;
442
    }
443

    
444
    public FeatureQuery getFeatureQuery() {
445
        return query;
446
    }
447

    
448
    /**
449
     * Loads all the Features of the current page.
450
     * @throws org.gvsig.tools.exception.BaseException
451
     */
452
    @Override
453
    protected synchronized void loadCurrentPageData() throws BaseException {
454
        if( !initialization_completed ) {
455
            return;
456
        }
457
        final int currentPageSize = getCalculator().getCurrentPageSize();
458
        final long currentPage = getCalculator().getCurrentPage();
459
        Page page = this.cachedPages.get(currentPage);
460
        if( page==null ) {
461
            page = new Page(currentPage, currentPageSize);
462

    
463
            long t1 = 0;
464
            if (LOG.isTraceEnabled()) {
465
                t1 = System.currentTimeMillis();
466
            }
467

    
468
            if (selectionUp) {
469
                loadCurrentPageDataWithSelectionUp(page);
470
            } else {
471
                loadCurrentPageDataNoSelection(page);
472
            }
473

    
474
            if (LOG.isTraceEnabled()) {
475
                long t2 = System.currentTimeMillis();
476
                LOG.trace("Time to load {} features: {} ms", currentPageSize, t2 - t1);
477
            }
478
            this.cachedPages.add(page);
479
        }
480
        this.features = page.getFeatures();
481
    }
482

    
483
    private void loadCurrentPageDataWithSelectionUp(final Page page)
484
            throws BaseException {
485
        FeatureSelection selection = initialSelection;
486
        if (selection == null) {
487
            loadCurrentPageDataNoSelection(page);
488
        } else {
489
            FeatureSet set = getFeatureSet(false);
490
            try {
491
                OneSubsetOneSetPagingCalculator twoSetsCalculator = null;
492
                if (getCalculator() instanceof OneSubsetOneSetPagingCalculator) {
493
                    twoSetsCalculator
494
                            = (OneSubsetOneSetPagingCalculator) getCalculator();
495
                } else {
496
                    twoSetsCalculator
497
                            = new OneSubsetOneSetPagingCalculator(
498
                                    new FeatureSetSizeableDelegate(selection),
499
                                    new FeatureSetSizeableDelegate(set),
500
                                    getMaxPageSize(), getCalculator().getCurrentPage());
501
                    setCalculator(twoSetsCalculator);
502
                }
503

    
504
                // First load values from the selection, if the current page has
505
                // elements from it
506
                if (twoSetsCalculator.hasCurrentPageAnyValuesInFirstSet()) {
507
                    loadDataFromFeatureSet(page, 0, selection,
508
                            twoSetsCalculator.getFirstSetInitialIndex(),
509
                            twoSetsCalculator.getFirstSetHowMany(), null);
510
                }
511
                // Next, load values from the FeatureSet if the current page has values
512
                // from it
513
                if (twoSetsCalculator.hasCurrentPageAnyValuesInSecondSet()) {
514
                    loadDataFromFeatureSet(
515
                            page,
516
                            // The cast will work as that size will be <= maxpagesize,
517
                            // which is an int
518
                            (int) twoSetsCalculator.getFirstSetHowMany(), set,
519
                            twoSetsCalculator.getSecondSetInitialIndex(),
520
                            twoSetsCalculator.getSecondSetHowMany(), selection);
521
                }
522
            } finally {
523
                /*
524
                 * This is the feature set
525
                 * we dont want to lose it
526
                 */
527
                // set.dispose();
528
            }
529
        }
530
    }
531

    
532
    private void loadCurrentPageDataNoSelection(final Page page)
533
        throws BaseException {
534

    
535
        long firstPosition = getCalculator().getInitialIndex();
536

    
537
        if (LOG.isDebugEnabled()) {
538
            LOG.debug("Loading {} Features starting at position {}", 
539
                getCalculator().getCurrentPageSize(), firstPosition
540
            );
541
        }
542

    
543
        FeatureSet featureSet = getFeatureSet(false);
544
        try {
545
                loadDataFromFeatureSet(page, 0, featureSet, firstPosition,
546
                                getCalculator().getCurrentPageSize(), null);
547
        } catch(DataException ex) {
548
            throw ex;
549
            // } finally {
550
                // featureSet.dispose();
551
        }
552

    
553
    }
554

    
555
    private void loadDataFromFeatureSet(final Page page,
556
        final int valuesPosition, FeatureSet set, long initialIndex,
557
        final long howMany, final FeatureSelection selectedFeaturesToSkip)
558
        throws DataException {
559

    
560
        try {
561
            final MutableBoolean errorReported = new MutableBoolean(false);
562
            set.accept(new Visitor() {
563
                private int i = valuesPosition;
564

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

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

    
615
        reloadCurrentPage();
616
    }
617

    
618
    public void insert(EditableFeature feature) throws BaseException {
619
            featureStore.insert(feature);
620
        /*
621
         * Force re-creation of feature set
622
         */
623
        this.getFeatureSet(true);
624

    
625
        reloadCurrentPage();
626
    }
627
    
628
    public boolean isEmpty() {
629
        try {
630
            return getFeatureSet(false).isEmpty();
631
        } catch (ConcurrentDataModificationException ex) {
632
            LOG.warn("ConcurrentDataModification error asking about the emptiness of the list. Retrying reloading data.");
633
            try {
634
                reload();
635
            } catch (BaseException e) {
636
                LOG.warn("Error reloading data.", e);
637
                throw new RuntimeException(e);
638
            }
639
            try {
640
                return getFeatureSet(false).isEmpty();
641
            } catch (DataException e) {
642
                LOG.warn("Error asking about the emptiness of the list after reloading data.",e);
643
                throw new RuntimeException(e);
644
            }
645
        } catch (DataException ex) {
646
            throw  new RuntimeException(ex);
647
        }
648
    }
649

    
650
    public void update(EditableFeature feature) throws BaseException {
651
            featureStore.update(feature);
652
        /*
653
         * Force re-creation of feature set
654
         */
655
        this.getFeatureSet(true);
656

    
657
        reloadCurrentPage();
658
    }
659

    
660
    public FeatureType getFeatureType() {
661

    
662
        FeatureType ft = null;
663

    
664
        try {
665
            ft = featureStore.getDefaultFeatureType();
666
        } catch (DataException e) {
667
            LOG.error("Error while getting feature type: " +
668
                e.getMessage(), e);
669
        }
670
        return ft;
671

    
672
        /*
673
         *
674
        FeatureSet featureSet = getFeatureSet();
675
        try {
676
            return featureSet.getDefaultFeatureType();
677
        } finally {
678
            featureSet.dispose();
679
        }
680
        */
681

    
682

    
683
    }
684

    
685
    protected void doDispose() throws BaseException {
686
        initialSelection.dispose();
687
        if (featSet != null) {
688
            try {
689
                featSet.dispose();
690
            } catch (Exception ex) {
691
                LOG.info("Error while disposing featset.", ex);
692
            }
693
        }
694
    }
695

    
696
    public DynObject[] getCurrentPageDynObjects() {
697
        Feature[] features = getCurrentPageFeatures();
698
        DynObject[] dynobjects = new DynObject[features.length];
699
        for (int i = 0; i < dynobjects.length; i++) {
700
            dynobjects[i] = new DynObjectFeatureFacade(features[i]);
701
        }
702
        return dynobjects;
703
    }
704

    
705
    @Override
706
    public DynObject getDynObjectAt(long index) throws BaseException {
707
        return new DynObjectFeatureFacade(getFeatureAt(index));
708
    }
709

    
710
    @Override
711
    public List asList() {
712
        return new FeaturePagingHelperList();
713
    }
714

    
715
    @Override
716
    public List asListOfDynObjects() {
717
        return new DynObjectPagingHelperList();
718
    }
719

    
720
    private class FeaturePagingHelperList extends PagingHelperList {
721
        @Override
722
        public Object get(int i) {
723
            return this.get64(i);
724
        }
725

    
726
        @Override
727
        public Object get64(long i) {
728
            try {
729
                return getFeatureAt(i);
730
            } catch (ConcurrentDataModificationException ex) {
731
                LOG.warn("ConcurrentDataModification error getting feature "+i+" of the list. Retrying reloading data.");
732
                try {
733
                    reload();
734
                } catch (BaseException e) {
735
                    LOG.warn("Error reloading data.", e);
736
                    throw new RuntimeException(e);
737
                }
738
                try {
739
                    return getFeatureAt(i);
740
                } catch (Exception e) {
741
                    LOG.warn("Error getting feature "+i+" of the list after reloading data.",e);
742
                    throw new RuntimeException(e);
743
                }
744
            } catch (BaseException ex) {
745
                throw  new RuntimeException(ex);
746
            }
747
        }
748

    
749
        @Override
750
        public Object set(int i, Object e) {
751
//            Feature newFeature = (Feature) e;
752
//            EditableFeature oldFeature = ((Feature) this.get(i)).getEditable();
753
//            oldFeature.copyFrom(newFeature);
754
//            update(oldFeature);
755
            return super.set(i, e);
756
        }
757

    
758
        @Override
759
        public Object remove(int i) {
760
//            Feature feature = (Feature) this.get(i);
761
//            delete(feature);
762
            return super.remove(i);
763
        }
764

    
765
        @Override
766
        public boolean add(Object e) {
767
//            EditableFeature feature = (EditableFeature) e;
768
//            insert(feature);
769
            return super.add(e);
770
        }
771
    }
772

    
773
    private class DynObjectPagingHelperList extends PagingHelperList {
774
        @Override
775
        public Object get(int i) {
776
            return this.get64(i);
777
        }
778

    
779
        @Override
780
        public Object get64(long position) {
781
            try {
782
                return getDynObjectAt(position);
783
            } catch (ConcurrentDataModificationException ex) {
784
                LOG.warn("ConcurrentDataModification error getting element "+position+" of the list. Retrying reloading data.");
785
                try {
786
                    reload();
787
                } catch (BaseException e) {
788
                    LOG.warn("Error reloading data.", e);
789
                    throw new RuntimeException(e);
790
                }
791
                try {
792
                    return getDynObjectAt(position);
793
                } catch (Exception e) {
794
                    LOG.warn("Error getting element "+position+" of the list after reloading data.",e);
795
                    throw new RuntimeException(e);
796
                }
797
            } catch (BaseException ex) {
798
                throw  new RuntimeException(ex);
799
            }
800
        }
801

    
802
    }
803

    
804
    private abstract class PagingHelperList implements List, FacadeOfAFeaturePagingHelper, UnmodifiableBasicList, UnmodifiableBasicList64 {
805

    
806
        @Override
807
        public FeaturePagingHelper getFeaturePagingHelper() {
808
            return FeaturePagingHelperImpl.this;
809
        }
810

    
811
        @Override
812
        public String toString() {
813
            return String.format("..(%d %ss)...", this.size(), featureStore.getName());
814
        }
815
        
816
        @Override
817
        public long size64() {
818
            try {
819
                return getFeatureSet(false).getSize();
820
            } catch (ConcurrentDataModificationException ex) {
821
                LOG.warn("ConcurrentDataModification error asking the size of the list. Retrying reloading data.");
822
                try {
823
                    reload();
824
                } catch (BaseException e) {
825
                    LOG.warn("Error reloading data.", e);
826
                    throw new RuntimeException(e);
827
                }
828
                try {
829
                    return getFeatureSet(false).getSize();
830
                } catch (DataException e) {
831
                    LOG.warn("Error asking the size of the list after reloading data.",e);
832
                    throw new RuntimeException(e);
833
                }
834
            } catch (DataException ex) {
835
                throw  new RuntimeException(ex);
836
            }
837
        }
838

    
839
        @Override
840
        public int size() {
841
            long sz = this.size64();
842
            if( sz>Integer.MAX_VALUE ) {
843
                sz = Integer.MAX_VALUE;
844
            }
845
            return (int) sz;
846
        }
847

    
848
        @Override
849
        public boolean isEmpty() {
850
            try {
851
                return getFeatureSet(false).isEmpty();
852
            } catch (ConcurrentDataModificationException ex) {
853
                LOG.warn("ConcurrentDataModification error asking about the emptiness of the list. Retrying reloading data.");
854
                try {
855
                    reload();
856
                } catch (BaseException e) {
857
                    LOG.warn("Error reloading data.", e);
858
                    throw new RuntimeException(e);
859
                }
860
                try {
861
                    return getFeatureSet(false).isEmpty();
862
                } catch (DataException e) {
863
                    LOG.warn("Error asking about the emptiness of the list after reloading data.",e);
864
                    throw new RuntimeException(e);
865
                }
866
            } catch (DataException ex) {
867
                throw  new RuntimeException(ex);
868
            }
869
        }
870

    
871
        @Override
872
        public Iterator iterator() {
873
            try {
874
                return getFeatureSet(false).fastIterator();
875
            } catch (ConcurrentDataModificationException ex) {
876
                LOG.warn("ConcurrentDataModification error getting iterator of the list. Retrying reloading data.");
877
                try {
878
                    reload();
879
                } catch (BaseException e) {
880
                    LOG.warn("Error reloading data.", e);
881
                    throw new RuntimeException(e);
882
                }
883
                try {
884
                    return getFeatureSet(false).fastIterator();
885
                } catch (DataException e) {
886
                    LOG.warn("Error getting iterator of the list after reloading data.",e);
887
                    throw new RuntimeException(e);
888
                }
889
            } catch (DataException ex) {
890
                throw  new RuntimeException(ex);
891
            }
892
        }
893

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

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

    
904
        @Override
905
        public Object[] toArray(Object[] ts) {
906
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
907
        }
908

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

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

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

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

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

    
934
        @Override
935
        public boolean removeAll(Collection clctn) {
936
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
937
        }
938

    
939
        @Override
940
        public boolean retainAll(Collection clctn) {
941
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
942
        }
943

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

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

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

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

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

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

    
974
        @Override
975
        public ListIterator listIterator() {
976
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
977
        }
978

    
979
        @Override
980
        public ListIterator listIterator(int i) {
981
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
982
        }
983

    
984
        @Override
985
        public List subList(int i, int i1) {
986
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
987
        }
988

    
989
        @Override
990
        public List toList() {
991
            return this;
992
        }
993

    
994
    }
995
}