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

History | View | Annotate | Download (33.4 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.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
public class FeaturePagingHelperImpl extends DefaultDynObjectPagingHelper
70
    implements FeaturePagingHelper {
71

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

    
74
    private static class Page {
75

    
76
        private Feature[] features;
77
        private final long number;
78
        private final int size;
79
        private long lastaccess;
80
        
81
        public Page(long number, int size) {
82
            this.size = size;
83
            this.number = number;
84
            this.features = new Feature[size];
85
            this.lastaccess = 0;
86
        }
87

    
88
        public void setFeature(int i, Feature copy) {
89
            this.features[i] = copy;
90
        }
91
        
92
        public Feature[] getFeatures() {
93
            this.lastaccess = (new Date()).getTime();
94
            return this.features;
95
        }
96
        
97
        public long getPageNumber() {
98
            return this.number;
99
        }
100
        
101
        public long getLastAccess() {
102
            return this.lastaccess;
103
        }
104
        
105
        public int size() {
106
            return this.size;
107
        }
108
        
109
        public void dispose() {
110
            for (int i = 0; i < features.length; i++) {
111
                features[i] = null;
112
            }
113
            this.features = null;
114
            this.lastaccess = 0;
115
        }
116
    } 
117
    
118
    private static class PageCache {
119

    
120
        private final int maxpages;
121
        private List<Page> pages;
122
        
123
        public PageCache(int maxpages) {
124
            this.maxpages = maxpages;
125
            this.pages = new ArrayList<>();
126
        }
127
        
128
        public void clear() {
129
            for (Page page : pages) {
130
                page.dispose();
131
            }
132
            this.pages = new ArrayList<>();    
133
        }
134
        
135
        public Page get(long pageNumber) {
136
            for( Page page : pages ) {
137
                if( page.getPageNumber() == pageNumber ) {
138
                    return page;
139
                }
140
            }
141
            return null;
142
        }
143
        
144
        public void add(Page page) {
145
            if( this.pages.size()< this.maxpages ) {
146
                this.pages.add(page);
147
                return;
148
            }
149
            int toDrop = 0;
150
            for( int i=0; i<this.pages.size(); i++ ) {
151
                if( this.pages.get(i).getLastAccess()<this.pages.get(toDrop).getLastAccess() ) {
152
                    toDrop = i;
153
                }
154
            }
155
            this.pages.set(toDrop, page);
156
        }
157
    }
158
    
159
    private FeatureQuery query;
160

    
161
    private FeatureStore featureStore;
162

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

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

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

    
172
    private boolean initialization_completed = false;
173

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

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

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

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

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

    
253

    
254
        if (LOG.isDebugEnabled()) {
255

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

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

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

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

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

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

    
340
    }
341

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

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

    
366
        if (featSet == null || reset) {
367

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

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

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

    
393
    @Override
394
    public void reloadCurrentPage() throws BaseException {
395

    
396
        boolean sel_up = this.isSelectionUp();
397

    
398
        setSelectionUp(false);
399
        if (getCalculator().getCurrentPage() > -1) {
400
            this.cachedPages.clear();
401
            loadCurrentPageData();
402
        }
403

    
404
        if (sel_up) {
405
            setSelectionUp(true);
406
        }
407
    }
408

    
409
    @Override
410
    public void reload() throws BaseException {
411

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

    
418

    
419
        setDefaultCalculator(new Sizeable() {
420
            public long getSize() {
421
                    FeatureSet featureSet = getFeatureSet(false);
422
                try {
423
                                        return featureSet.getSize();
424
                } catch (BaseException e) {
425
                    LOG.error("Error getting the size of the FeatureSet: "
426
                        + featureSet, e);
427
                    return 0l;
428
                }
429
            }
430
        }, getCalculator().getMaxPageSize());
431
        reloadCurrentPage();
432
    }
433

    
434
    public FeatureStore getFeatureStore() {
435
        return featureStore;
436
    }
437

    
438
    public FeatureQuery getFeatureQuery() {
439
        return query;
440
    }
441

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

    
457
            long t1 = 0;
458
            if (LOG.isTraceEnabled()) {
459
                t1 = System.currentTimeMillis();
460
            }
461

    
462
            if (selectionUp) {
463
                loadCurrentPageDataWithSelectionUp(page);
464
            } else {
465
                loadCurrentPageDataNoSelection(page);
466
            }
467

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

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

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

    
526
    private void loadCurrentPageDataNoSelection(final Page page)
527
        throws BaseException {
528

    
529
        long firstPosition = getCalculator().getInitialIndex();
530

    
531
        if (LOG.isDebugEnabled()) {
532
            LOG.debug("Loading {} Features starting at position {}", 
533
                getCalculator().getCurrentPageSize(), firstPosition
534
            );
535
        }
536

    
537
        FeatureSet featureSet = getFeatureSet(false);
538
        try {
539
                loadDataFromFeatureSet(page, 0, featureSet, firstPosition,
540
                                getCalculator().getCurrentPageSize(), null);
541
        } catch(DataException ex) {
542
            throw ex;
543
            // } finally {
544
                // featureSet.dispose();
545
        }
546

    
547
    }
548

    
549
    private void loadDataFromFeatureSet(final Page page,
550
        final int valuesPosition, FeatureSet set, long initialIndex,
551
        final long howMany, final FeatureSelection selectedFeaturesToSkip)
552
        throws DataException {
553

    
554
        try {
555
            set.accept(new Visitor() {
556
                private int i = valuesPosition;
557

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

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

    
603
        reloadCurrentPage();
604
    }
605

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

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

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

    
645
        reloadCurrentPage();
646
    }
647

    
648
    public FeatureType getFeatureType() {
649

    
650
        FeatureType ft = null;
651

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

    
660
        /*
661
         *
662
        FeatureSet featureSet = getFeatureSet();
663
        try {
664
            return featureSet.getDefaultFeatureType();
665
        } finally {
666
            featureSet.dispose();
667
        }
668
        */
669

    
670

    
671
    }
672

    
673
    protected void doDispose() throws BaseException {
674
        initialSelection.dispose();
675
        if (featSet != null) {
676
            try {
677
                featSet.dispose();
678
            } catch (Exception ex) {
679
                LOG.info("Error while disposing featset.", ex);
680
            }
681
        }
682
    }
683

    
684
    public DynObject[] getCurrentPageDynObjects() {
685
        Feature[] features = getCurrentPageFeatures();
686
        DynObject[] dynobjects = new DynObject[features.length];
687
        for (int i = 0; i < dynobjects.length; i++) {
688
            dynobjects[i] = new DynObjectFeatureFacade(features[i]);
689
        }
690
        return dynobjects;
691
    }
692

    
693
    @Override
694
    public DynObject getDynObjectAt(long index) throws BaseException {
695
        return new DynObjectFeatureFacade(getFeatureAt(index));
696
    }
697

    
698
    @Override
699
    public List asList() {
700
        return new FeaturePagingHelperList();
701
    }
702

    
703
    @Override
704
    public List asListOfDynObjects() {
705
        return new DynObjectPagingHelperList();
706
    }
707

    
708
    private class FeaturePagingHelperList extends PagingHelperList {
709
        @Override
710
        public Object get(int i) {
711
            return this.get64(i);
712
        }
713

    
714
        @Override
715
        public Object get64(long i) {
716
            try {
717
                return getFeatureAt(i);
718
            } catch (ConcurrentDataModificationException ex) {
719
                LOG.warn("ConcurrentDataModification error getting feature "+i+" of the list. Retrying reloading data.");
720
                try {
721
                    reload();
722
                } catch (BaseException e) {
723
                    LOG.warn("Error reloading data.", e);
724
                    throw new RuntimeException(e);
725
                }
726
                try {
727
                    return getFeatureAt(i);
728
                } catch (Exception e) {
729
                    LOG.warn("Error getting feature "+i+" of the list after reloading data.",e);
730
                    throw new RuntimeException(e);
731
                }
732
            } catch (BaseException ex) {
733
                throw  new RuntimeException(ex);
734
            }
735
        }
736

    
737
        @Override
738
        public Object set(int i, Object e) {
739
//            Feature newFeature = (Feature) e;
740
//            EditableFeature oldFeature = ((Feature) this.get(i)).getEditable();
741
//            oldFeature.copyFrom(newFeature);
742
//            update(oldFeature);
743
            return super.set(i, e);
744
        }
745

    
746
        @Override
747
        public Object remove(int i) {
748
//            Feature feature = (Feature) this.get(i);
749
//            delete(feature);
750
            return super.remove(i);
751
        }
752

    
753
        @Override
754
        public boolean add(Object e) {
755
//            EditableFeature feature = (EditableFeature) e;
756
//            insert(feature);
757
            return super.add(e);
758
        }
759
    }
760

    
761
    private class DynObjectPagingHelperList extends PagingHelperList {
762
        @Override
763
        public Object get(int i) {
764
            return this.get64(i);
765
        }
766

    
767
        @Override
768
        public Object get64(long position) {
769
            try {
770
                return getDynObjectAt(position);
771
            } catch (ConcurrentDataModificationException ex) {
772
                LOG.warn("ConcurrentDataModification error getting element "+position+" of the list. Retrying reloading data.");
773
                try {
774
                    reload();
775
                } catch (BaseException e) {
776
                    LOG.warn("Error reloading data.", e);
777
                    throw new RuntimeException(e);
778
                }
779
                try {
780
                    return getDynObjectAt(position);
781
                } catch (Exception e) {
782
                    LOG.warn("Error getting element "+position+" of the list after reloading data.",e);
783
                    throw new RuntimeException(e);
784
                }
785
            } catch (BaseException ex) {
786
                throw  new RuntimeException(ex);
787
            }
788
        }
789

    
790
    }
791

    
792
    private abstract class PagingHelperList implements List, FacadeOfAFeaturePagingHelper, UnmodifiableBasicList, UnmodifiableBasicList64 {
793

    
794
        @Override
795
        public FeaturePagingHelper getFeaturePagingHelper() {
796
            return FeaturePagingHelperImpl.this;
797
        }
798

    
799
        @Override
800
        public String toString() {
801
            return String.format("..(%d %ss)...", this.size(), featureStore.getName());
802
        }
803
        
804
        @Override
805
        public long size64() {
806
            try {
807
                return getFeatureSet(false).getSize();
808
            } catch (ConcurrentDataModificationException ex) {
809
                LOG.warn("ConcurrentDataModification error asking the size of the list. Retrying reloading data.");
810
                try {
811
                    reload();
812
                } catch (BaseException e) {
813
                    LOG.warn("Error reloading data.", e);
814
                    throw new RuntimeException(e);
815
                }
816
                try {
817
                    return getFeatureSet(false).getSize();
818
                } catch (DataException e) {
819
                    LOG.warn("Error asking the size of the list after reloading data.",e);
820
                    throw new RuntimeException(e);
821
                }
822
            } catch (DataException ex) {
823
                throw  new RuntimeException(ex);
824
            }
825
        }
826

    
827
        @Override
828
        public int size() {
829
            long sz = this.size64();
830
            if( sz>Integer.MAX_VALUE ) {
831
                sz = Integer.MAX_VALUE;
832
            }
833
            return (int) sz;
834
        }
835

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
977
        @Override
978
        public List toList() {
979
            return this;
980
        }
981

    
982
    }
983
}