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

History | View | Annotate | Download (33.5 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
    @Override
359
    public FeatureSet getFeatureSet() {
360
        return this.getFeatureSet(false);
361
    }
362

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

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

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

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

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

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

    
401
        boolean sel_up = this.isSelectionUp();
402

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

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

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

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

    
423

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

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

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

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

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

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

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

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

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

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

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

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

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

    
552
    }
553

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

    
559
        try {
560
            set.accept(new Visitor() {
561
                private int i = valuesPosition;
562

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

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

    
608
        reloadCurrentPage();
609
    }
610

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

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

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

    
650
        reloadCurrentPage();
651
    }
652

    
653
    public FeatureType getFeatureType() {
654

    
655
        FeatureType ft = null;
656

    
657
        try {
658
            ft = featureStore.getDefaultFeatureType();
659
        } catch (DataException e) {
660
            LOG.error("Error while getting feature type: " +
661
                e.getMessage(), e);
662
        }
663
        return ft;
664

    
665
        /*
666
         *
667
        FeatureSet featureSet = getFeatureSet();
668
        try {
669
            return featureSet.getDefaultFeatureType();
670
        } finally {
671
            featureSet.dispose();
672
        }
673
        */
674

    
675

    
676
    }
677

    
678
    protected void doDispose() throws BaseException {
679
        initialSelection.dispose();
680
        if (featSet != null) {
681
            try {
682
                featSet.dispose();
683
            } catch (Exception ex) {
684
                LOG.info("Error while disposing featset.", ex);
685
            }
686
        }
687
    }
688

    
689
    public DynObject[] getCurrentPageDynObjects() {
690
        Feature[] features = getCurrentPageFeatures();
691
        DynObject[] dynobjects = new DynObject[features.length];
692
        for (int i = 0; i < dynobjects.length; i++) {
693
            dynobjects[i] = new DynObjectFeatureFacade(features[i]);
694
        }
695
        return dynobjects;
696
    }
697

    
698
    @Override
699
    public DynObject getDynObjectAt(long index) throws BaseException {
700
        return new DynObjectFeatureFacade(getFeatureAt(index));
701
    }
702

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

    
708
    @Override
709
    public List asListOfDynObjects() {
710
        return new DynObjectPagingHelperList();
711
    }
712

    
713
    private class FeaturePagingHelperList extends PagingHelperList {
714
        @Override
715
        public Object get(int i) {
716
            return this.get64(i);
717
        }
718

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

    
742
        @Override
743
        public Object set(int i, Object e) {
744
//            Feature newFeature = (Feature) e;
745
//            EditableFeature oldFeature = ((Feature) this.get(i)).getEditable();
746
//            oldFeature.copyFrom(newFeature);
747
//            update(oldFeature);
748
            return super.set(i, e);
749
        }
750

    
751
        @Override
752
        public Object remove(int i) {
753
//            Feature feature = (Feature) this.get(i);
754
//            delete(feature);
755
            return super.remove(i);
756
        }
757

    
758
        @Override
759
        public boolean add(Object e) {
760
//            EditableFeature feature = (EditableFeature) e;
761
//            insert(feature);
762
            return super.add(e);
763
        }
764
    }
765

    
766
    private class DynObjectPagingHelperList extends PagingHelperList {
767
        @Override
768
        public Object get(int i) {
769
            return this.get64(i);
770
        }
771

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

    
795
    }
796

    
797
    private abstract class PagingHelperList implements List, FacadeOfAFeaturePagingHelper, UnmodifiableBasicList, UnmodifiableBasicList64 {
798

    
799
        @Override
800
        public FeaturePagingHelper getFeaturePagingHelper() {
801
            return FeaturePagingHelperImpl.this;
802
        }
803

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

    
832
        @Override
833
        public int size() {
834
            long sz = this.size64();
835
            if( sz>Integer.MAX_VALUE ) {
836
                sz = Integer.MAX_VALUE;
837
            }
838
            return (int) sz;
839
        }
840

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

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

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

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

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

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

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

    
912
        @Override
913
        public boolean containsAll(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(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 addAll(int i, 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 removeAll(Collection clctn) {
929
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
930
        }
931

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

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

    
942
        @Override
943
        public Object set(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 void add(int i, Object e) {
949
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
950
        }
951

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

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

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

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

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

    
977
        @Override
978
        public List subList(int i, int i1) {
979
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
980
        }
981

    
982
        @Override
983
        public List toList() {
984
            return this;
985
        }
986

    
987
    }
988
}