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

History | View | Annotate | Download (34 KB)

1 40559 jjdelcerro
/**
2
 * gvSIG. Desktop Geographic Information System.
3 40435 jjdelcerro
 *
4 44977 jjdelcerro
 * Copyright (C) 2007-2020 gvSIG Association.
5 40435 jjdelcerro
 *
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 40559 jjdelcerro
 * as published by the Free Software Foundation; either version 3
9 40435 jjdelcerro
 * 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 40559 jjdelcerro
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23 40435 jjdelcerro
 */
24
package org.gvsig.fmap.dal.feature.paging.impl;
25
26 43660 jjdelcerro
import java.util.ArrayList;
27 41212 jjdelcerro
import java.util.Collection;
28 43660 jjdelcerro
import java.util.Date;
29 41212 jjdelcerro
import java.util.Iterator;
30
import java.util.List;
31
import java.util.ListIterator;
32 45425 jjdelcerro
import java.util.logging.Level;
33 44840 jjdelcerro
import org.apache.commons.lang3.mutable.MutableBoolean;
34 40435 jjdelcerro
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 41819 fdiaz
import org.gvsig.fmap.dal.feature.exception.ConcurrentDataModificationException;
46 40435 jjdelcerro
import org.gvsig.fmap.dal.feature.exception.FeatureIndexException;
47 42775 jjdelcerro
import org.gvsig.fmap.dal.feature.impl.dynobjectutils.DynObjectFeatureFacade;
48
import org.gvsig.fmap.dal.feature.paging.FacadeOfAFeaturePagingHelper;
49 40435 jjdelcerro
import org.gvsig.fmap.dal.feature.paging.FeaturePagingHelper;
50 45196 jjdelcerro
import org.gvsig.tools.dispose.Disposable;
51 45425 jjdelcerro
import org.gvsig.tools.dispose.DisposeUtils;
52 40435 jjdelcerro
import org.gvsig.tools.dynobject.DynObject;
53
import org.gvsig.tools.dynobject.DynObjectSet;
54
import org.gvsig.tools.dynobject.impl.DefaultDynObjectPagingHelper;
55
import org.gvsig.tools.exception.BaseException;
56 44253 jjdelcerro
import org.gvsig.tools.util.UnmodifiableBasicList;
57
import org.gvsig.tools.util.UnmodifiableBasicList64;
58 40435 jjdelcerro
import org.gvsig.tools.visitor.VisitCanceledException;
59
import org.gvsig.tools.visitor.Visitor;
60
61
/**
62
 * Helper class to access the values of a FeatureCollection by position. Handles
63
 * pagination automatically to avoid filling the memory in case of big
64
 * collections.
65 41819 fdiaz
 *
66 40435 jjdelcerro
 * TODO: evaluate if its more convenient to read values in the background when
67
 * the returned value is near the end of the page, instead of loading a page on
68
 * demand.
69 41819 fdiaz
 *
70 40435 jjdelcerro
 * @author gvSIG Team
71
 */
72 44977 jjdelcerro
@SuppressWarnings("UseSpecificCatch")
73 40435 jjdelcerro
public class FeaturePagingHelperImpl extends DefaultDynObjectPagingHelper
74 44977 jjdelcerro
        implements FeaturePagingHelper {
75 40435 jjdelcerro
76 43660 jjdelcerro
    private static final Logger LOG = LoggerFactory.getLogger(FeaturePagingHelperImpl.class);
77 40435 jjdelcerro
78 43660 jjdelcerro
    private static class Page {
79
80 43691 jjdelcerro
        private Feature[] features;
81 43660 jjdelcerro
        private final long number;
82
        private final int size;
83
        private long lastaccess;
84 44977 jjdelcerro
85 43660 jjdelcerro
        public Page(long number, int size) {
86
            this.size = size;
87
            this.number = number;
88
            this.features = new Feature[size];
89
            this.lastaccess = 0;
90
        }
91
92
        public void setFeature(int i, Feature copy) {
93
            this.features[i] = copy;
94
        }
95 44977 jjdelcerro
96 43660 jjdelcerro
        public Feature[] getFeatures() {
97
            this.lastaccess = (new Date()).getTime();
98
            return this.features;
99
        }
100 44977 jjdelcerro
101 43660 jjdelcerro
        public long getPageNumber() {
102
            return this.number;
103
        }
104 44977 jjdelcerro
105 43660 jjdelcerro
        public long getLastAccess() {
106
            return this.lastaccess;
107
        }
108 44977 jjdelcerro
109 43660 jjdelcerro
        public int size() {
110
            return this.size;
111
        }
112 44977 jjdelcerro
113 43691 jjdelcerro
        public void dispose() {
114
            for (int i = 0; i < features.length; i++) {
115
                features[i] = null;
116
            }
117
            this.features = null;
118
            this.lastaccess = 0;
119
        }
120 44977 jjdelcerro
    }
121
122 43660 jjdelcerro
    private static class PageCache {
123
124
        private final int maxpages;
125 43691 jjdelcerro
        private List<Page> pages;
126 44977 jjdelcerro
127 43660 jjdelcerro
        public PageCache(int maxpages) {
128
            this.maxpages = maxpages;
129
            this.pages = new ArrayList<>();
130
        }
131 44977 jjdelcerro
132 43691 jjdelcerro
        public void clear() {
133 44977 jjdelcerro
            pages.forEach((page) -> {
134 43691 jjdelcerro
                page.dispose();
135 44977 jjdelcerro
            });
136
            this.pages = new ArrayList<>();
137 43691 jjdelcerro
        }
138 44977 jjdelcerro
139 43660 jjdelcerro
        public Page get(long pageNumber) {
140 44977 jjdelcerro
            for (Page page : pages) {
141
                if (page.getPageNumber() == pageNumber) {
142 43660 jjdelcerro
                    return page;
143
                }
144
            }
145
            return null;
146
        }
147 44977 jjdelcerro
148 43660 jjdelcerro
        public void add(Page page) {
149 44977 jjdelcerro
            if (this.pages.size() < this.maxpages) {
150 43660 jjdelcerro
                this.pages.add(page);
151
                return;
152
            }
153
            int toDrop = 0;
154 44977 jjdelcerro
            for (int i = 0; i < this.pages.size(); i++) {
155
                if (this.pages.get(i).getLastAccess() < this.pages.get(toDrop).getLastAccess()) {
156 43660 jjdelcerro
                    toDrop = i;
157
                }
158
            }
159
            this.pages.set(toDrop, page);
160
        }
161
    }
162 44977 jjdelcerro
163 40435 jjdelcerro
    private FeatureQuery query;
164
165
    private FeatureStore featureStore;
166
167 44977 jjdelcerro
    /**
168
     * If the selected Features must be returned as the first ones. *
169
     */
170 40435 jjdelcerro
    private boolean selectionUp = false;
171
172
    private FeatureSet featSet = null;
173
174
    private Feature[] features = null;
175 43660 jjdelcerro
    private PageCache cachedPages = null;
176 40435 jjdelcerro
177 41212 jjdelcerro
    private boolean initialization_completed = false;
178 42807 jjdelcerro
179
    private FeatureSelection selection = null;
180 44977 jjdelcerro
181 40435 jjdelcerro
    /**
182
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
183 41819 fdiaz
     *
184 44977 jjdelcerro
     * @param featureStore to extract data from
185
     * @throws DataException if there is an error initializing the helper
186 40435 jjdelcerro
     */
187
    public FeaturePagingHelperImpl(FeatureStore featureStore)
188 44977 jjdelcerro
            throws BaseException {
189 40435 jjdelcerro
        this(featureStore, DEFAULT_PAGE_SIZE);
190
    }
191
192
    /**
193
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
194 41819 fdiaz
     *
195 44977 jjdelcerro
     * @param featureStore to extract data from
196
     * @param pageSize the number of elements per page data
197
     * @throws DataException if there is an error initializing the helper
198 40435 jjdelcerro
     */
199
    public FeaturePagingHelperImpl(FeatureStore featureStore, int pageSize)
200 44977 jjdelcerro
            throws BaseException {
201 40435 jjdelcerro
        this(featureStore, null, pageSize);
202
    }
203
204
    /**
205
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
206 41819 fdiaz
     *
207 44977 jjdelcerro
     * @param featureStore to extract data from
208
     * @param featureQuery
209
     * @throws DataException if there is an error initializing the helper
210 40435 jjdelcerro
     */
211
    public FeaturePagingHelperImpl(FeatureStore featureStore,
212 44977 jjdelcerro
            FeatureQuery featureQuery) throws BaseException {
213 40435 jjdelcerro
        this(featureStore, featureQuery, DEFAULT_PAGE_SIZE);
214
    }
215
216
    /**
217
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
218 41819 fdiaz
     *
219 44977 jjdelcerro
     * @param featureStore
220
     * @param featureQuery
221
     * @param pageSize the number of elements per page data
222
     * @throws DataException if there is an error initializing the helper
223 40435 jjdelcerro
     */
224
    public FeaturePagingHelperImpl(FeatureStore featureStore,
225 44977 jjdelcerro
            FeatureQuery featureQuery, int pageSize) throws BaseException {
226 40435 jjdelcerro
        super();
227 43660 jjdelcerro
        this.cachedPages = new PageCache(3);
228 44977 jjdelcerro
        FeatureQuery theQuery = featureQuery;
229 40435 jjdelcerro
        if (featureQuery == null) {
230 44977 jjdelcerro
            theQuery = featureStore.createFeatureQuery();
231
            theQuery.setFeatureType(featureStore.getDefaultFeatureType());
232 40435 jjdelcerro
        }
233
234
        this.featureStore = featureStore;
235 45425 jjdelcerro
        DisposeUtils.bind(this.featureStore);
236
237 44977 jjdelcerro
        this.query = theQuery;
238 40435 jjdelcerro
        this.query.setPageSize(pageSize);
239
240 44977 jjdelcerro
        setDefaultCalculator(() -> {
241
            FeatureSet featureSet = getFeatureSet(false);
242
            try {
243
                return featureSet.getSize();
244
            } catch (BaseException e) {
245
                LOG.warn("Error getting the size of the FeatureSet: " + featureSet, e);
246
                return 0l;
247 40435 jjdelcerro
            }
248
        }, pageSize);
249 40595 jldominguez
        if (LOG.isDebugEnabled()) {
250 44977 jjdelcerro
            LOG.debug("FeaturePagingHelperImpl created with {} pages, and a page size of {}",
251
                    getCalculator().getNumPages(), pageSize
252
            );
253 40595 jldominguez
        }
254 41212 jjdelcerro
        this.initialization_completed = true;
255 40435 jjdelcerro
    }
256
257
    /**
258
     * @return the selectionUp status
259
     */
260 44977 jjdelcerro
    @Override
261 41630 jjdelcerro
    public boolean isSelectionUp() {
262 40435 jjdelcerro
        return selectionUp;
263
    }
264 44977 jjdelcerro
265
    @Override
266 42807 jjdelcerro
    public FeatureSelection getSelection() {
267
        if (selection == null) {
268
            try {
269
                return getFeatureStore().getFeatureSelection();
270
            } catch (Exception e) {
271
                LOG.warn("Error getting the selection", e);
272
            }
273
        }
274
        return selection;
275
    }
276 44977 jjdelcerro
277
    @Override
278 42807 jjdelcerro
    public void setSelection(FeatureSelection selection) {
279
        this.selection = selection;
280
    }
281 44977 jjdelcerro
282 42807 jjdelcerro
    @Override
283 40435 jjdelcerro
    public void setSelectionUp(boolean selectionUp) {
284
        this.selectionUp = selectionUp;
285
        try {
286 43728 jjdelcerro
            this.cachedPages.clear();
287 42807 jjdelcerro
            FeatureSelection currentSelection = getSelection();
288 41630 jjdelcerro
            if (selectionUp && !currentSelection.isEmpty()) {
289 44977 jjdelcerro
//                initialSelection =(FeatureSelection) currentSelection.clone();
290 40435 jjdelcerro
                setCalculator(new OneSubsetOneSetPagingCalculator(
291 44977 jjdelcerro
                        new FeatureSetSizeableDelegate(currentSelection),
292
                        new FeatureSetSizeableDelegate(getFeatureSet(false)),
293
                        getMaxPageSize()));
294 40435 jjdelcerro
            } else {
295
                setDefaultCalculator(new FeatureSetSizeableDelegate(
296 44977 jjdelcerro
                        getFeatureSet(false)), getMaxPageSize()
297
                );
298 40435 jjdelcerro
            }
299
        } catch (BaseException e) {
300 44977 jjdelcerro
            LOG.warn("Error setting the selection up setting to: " + selectionUp, e);
301 40435 jjdelcerro
        }
302
    }
303
304 44977 jjdelcerro
    @Override
305 42991 jbadia
    public synchronized Feature getFeatureAt(long index) throws BaseException {
306 40435 jjdelcerro
        // Check if we have currently loaded the viewed page data,
307
        // or we need to load a new one
308 44977 jjdelcerro
        int maxPageSize = getMaxPageSize();
309
        long currentPage = getCurrentPage();
310
        long currentPage2 = currentPage;
311
312 42991 jbadia
        long pageForIndex = (long) Math.floor(index / maxPageSize);
313 40435 jjdelcerro
314 42991 jbadia
        if (pageForIndex != currentPage) {
315 40435 jjdelcerro
            setCurrentPage(pageForIndex);
316 42991 jbadia
            currentPage2 = getCurrentPage();
317 40435 jjdelcerro
        }
318
319 42991 jbadia
        long positionForIndex = index - (currentPage2 * maxPageSize);
320 40435 jjdelcerro
321 41268 jjdelcerro
        if (positionForIndex >= getCurrentPageFeatures().length) {
322 40435 jjdelcerro
            throw new FeatureIndexException(
323 44977 jjdelcerro
                    new IndexOutOfBoundsException("positionForIndex too big: "
324
                            + positionForIndex));
325 40435 jjdelcerro
        } else {
326 41268 jjdelcerro
            Feature feature = getCurrentPageFeatures()[(int) positionForIndex];
327 41212 jjdelcerro
            return feature;
328 40435 jjdelcerro
        }
329 41819 fdiaz
330 40435 jjdelcerro
    }
331
332 44977 jjdelcerro
    @Override
333 40435 jjdelcerro
    public Feature[] getCurrentPageFeatures() {
334 44977 jjdelcerro
        if (this.features == null) {
335 41268 jjdelcerro
            try {
336
                this.loadCurrentPageData();
337
            } catch (BaseException ex) {
338
                // Do nothing
339
            }
340 44977 jjdelcerro
            if (this.features == null) {
341 41268 jjdelcerro
                String msg = "Can't retrieve the features from current page.";
342
                LOG.warn(msg);
343
                throw new RuntimeException(msg);
344
            }
345
        }
346 40435 jjdelcerro
        return features;
347
    }
348 44977 jjdelcerro
349 44794 omartinez
    @Override
350
    public FeatureSet getFeatureSet() {
351
        return this.getFeatureSet(false);
352
    }
353 40435 jjdelcerro
354
    /**
355 44977 jjdelcerro
     * Gets the feature set. The boolean tells whether we must create the
356
     * featureset again (for example perhaps we need it after a feature has been
357
     * added/removed)
358 40435 jjdelcerro
     */
359
    private FeatureSet getFeatureSet(boolean reset) {
360 41819 fdiaz
361 40435 jjdelcerro
        if (featSet == null || reset) {
362 41819 fdiaz
363 40435 jjdelcerro
            if (featSet != null) {
364
                try {
365
                    featSet.dispose();
366
                } catch (Exception ex) {
367
                    LOG.info("Error while disposing featset.", ex);
368
                }
369
            }
370 41819 fdiaz
371 40435 jjdelcerro
            try {
372 41819 fdiaz
                FeatureStore featureStore = getFeatureStore();
373 40435 jjdelcerro
                synchronized (featureStore) {
374 41819 fdiaz
                    featSet = featureStore.getFeatureSet(getFeatureQuery());
375 40435 jjdelcerro
                }
376
            } catch (DataException e) {
377
                throw new RuntimeException("Error getting a feature set with the query " + getFeatureQuery());
378
            }
379
        }
380
        return featSet;
381
    }
382 41819 fdiaz
383 43691 jjdelcerro
    @Override
384 40435 jjdelcerro
    public DynObjectSet getDynObjectSet() {
385 44977 jjdelcerro
        return getFeatureSet(false).getDynObjectSet();
386 40435 jjdelcerro
    }
387
388 43691 jjdelcerro
    @Override
389 40435 jjdelcerro
    public void reloadCurrentPage() throws BaseException {
390
        boolean sel_up = this.isSelectionUp();
391 44977 jjdelcerro
        try {
392
            setSelectionUp(false);
393
            if (getCalculator().getCurrentPage() > -1) {
394
                this.cachedPages.clear();
395
                loadCurrentPageData();
396
            }
397
        } finally {
398
            if (sel_up) {
399
                setSelectionUp(true);
400
            }
401 40435 jjdelcerro
        }
402
    }
403
404 43691 jjdelcerro
    @Override
405 40435 jjdelcerro
    public void reload() throws BaseException {
406 41819 fdiaz
407 43726 jjdelcerro
        this.cachedPages.clear();
408 40435 jjdelcerro
        /*
409
         * Force re-creation of feature set
410
         */
411
        this.getFeatureSet(true);
412
413 44977 jjdelcerro
        setDefaultCalculator(() -> {
414
            FeatureSet featureSet = getFeatureSet(false);
415
            try {
416
                return featureSet.getSize();
417
            } catch (BaseException e) {
418
                LOG.warn("Error getting the size of the FeatureSet: "+ featureSet, e);
419
                return 0l;
420 40435 jjdelcerro
            }
421
        }, getCalculator().getMaxPageSize());
422 45154 jjdelcerro
//        reloadCurrentPage();
423 40435 jjdelcerro
    }
424
425 44977 jjdelcerro
    @Override
426 40435 jjdelcerro
    public FeatureStore getFeatureStore() {
427
        return featureStore;
428
    }
429
430 44977 jjdelcerro
    @Override
431 40435 jjdelcerro
    public FeatureQuery getFeatureQuery() {
432
        return query;
433
    }
434
435
    /**
436
     * Loads all the Features of the current page.
437 44977 jjdelcerro
     *
438 43660 jjdelcerro
     * @throws org.gvsig.tools.exception.BaseException
439 40435 jjdelcerro
     */
440 43660 jjdelcerro
    @Override
441 42991 jbadia
    protected synchronized void loadCurrentPageData() throws BaseException {
442 44977 jjdelcerro
        if (!initialization_completed) {
443 41212 jjdelcerro
            return;
444
        }
445 40435 jjdelcerro
        final int currentPageSize = getCalculator().getCurrentPageSize();
446 43660 jjdelcerro
        final long currentPage = getCalculator().getCurrentPage();
447
        Page page = this.cachedPages.get(currentPage);
448 44977 jjdelcerro
        if (page == null) {
449 43660 jjdelcerro
            page = new Page(currentPage, currentPageSize);
450 40435 jjdelcerro
451 43660 jjdelcerro
            long t1 = 0;
452
            if (LOG.isTraceEnabled()) {
453
                t1 = System.currentTimeMillis();
454
            }
455 40435 jjdelcerro
456 43660 jjdelcerro
            if (selectionUp) {
457
                loadCurrentPageDataWithSelectionUp(page);
458
            } else {
459
                loadCurrentPageDataNoSelection(page);
460
            }
461 40435 jjdelcerro
462 43660 jjdelcerro
            if (LOG.isTraceEnabled()) {
463
                long t2 = System.currentTimeMillis();
464
                LOG.trace("Time to load {} features: {} ms", currentPageSize, t2 - t1);
465
            }
466
            this.cachedPages.add(page);
467 40435 jjdelcerro
        }
468 43660 jjdelcerro
        this.features = page.getFeatures();
469 40435 jjdelcerro
    }
470 41819 fdiaz
471 43660 jjdelcerro
    private void loadCurrentPageDataWithSelectionUp(final Page page)
472 41630 jjdelcerro
            throws BaseException {
473 44977 jjdelcerro
        FeatureSelection theSelection = getSelection();
474
        if (theSelection == null) {
475 43660 jjdelcerro
            loadCurrentPageDataNoSelection(page);
476 41630 jjdelcerro
        } else {
477
            FeatureSet set = getFeatureSet(false);
478
            try {
479
                OneSubsetOneSetPagingCalculator twoSetsCalculator = null;
480
                if (getCalculator() instanceof OneSubsetOneSetPagingCalculator) {
481 44977 jjdelcerro
                    twoSetsCalculator = (OneSubsetOneSetPagingCalculator) getCalculator();
482 41630 jjdelcerro
                } else {
483 44977 jjdelcerro
                    twoSetsCalculator = new OneSubsetOneSetPagingCalculator(
484
                                    new FeatureSetSizeableDelegate(theSelection),
485 41630 jjdelcerro
                                    new FeatureSetSizeableDelegate(set),
486 44977 jjdelcerro
                                    getMaxPageSize(), getCalculator().getCurrentPage()
487
                    );
488 41630 jjdelcerro
                    setCalculator(twoSetsCalculator);
489
                }
490 44977 jjdelcerro
                // First load values from the selection, if the current page has
491 41630 jjdelcerro
                // elements from it
492
                if (twoSetsCalculator.hasCurrentPageAnyValuesInFirstSet()) {
493 44977 jjdelcerro
                    loadDataFromFeatureSet(page, 0, theSelection,
494 41630 jjdelcerro
                            twoSetsCalculator.getFirstSetInitialIndex(),
495 44977 jjdelcerro
                            twoSetsCalculator.getFirstSetHowMany(), null
496
                    );
497 41630 jjdelcerro
                }
498 44977 jjdelcerro
                // Next, load values from the FeatureSet if the current page has values
499 41630 jjdelcerro
                // from it
500
                if (twoSetsCalculator.hasCurrentPageAnyValuesInSecondSet()) {
501
                    loadDataFromFeatureSet(
502 43660 jjdelcerro
                            page,
503 41630 jjdelcerro
                            // The cast will work as that size will be <= maxpagesize,
504
                            // which is an int
505
                            (int) twoSetsCalculator.getFirstSetHowMany(), set,
506
                            twoSetsCalculator.getSecondSetInitialIndex(),
507 44977 jjdelcerro
                            twoSetsCalculator.getSecondSetHowMany(), theSelection
508
                    );
509 41630 jjdelcerro
                }
510
            } finally {
511 44977 jjdelcerro
                // This is the feature set we dont want to lose it
512 41630 jjdelcerro
                // set.dispose();
513
            }
514 40435 jjdelcerro
        }
515
    }
516
517 43660 jjdelcerro
    private void loadCurrentPageDataNoSelection(final Page page)
518 44977 jjdelcerro
            throws BaseException {
519 40435 jjdelcerro
520
        long firstPosition = getCalculator().getInitialIndex();
521
522
        if (LOG.isDebugEnabled()) {
523 44977 jjdelcerro
            LOG.debug("Loading {} Features starting at position {}",
524
                    getCalculator().getCurrentPageSize(), firstPosition
525 43660 jjdelcerro
            );
526 40435 jjdelcerro
        }
527
528
        FeatureSet featureSet = getFeatureSet(false);
529
        try {
530 44977 jjdelcerro
            loadDataFromFeatureSet(page, 0, featureSet, firstPosition,
531
                    getCalculator().getCurrentPageSize(), null);
532
        } catch (DataException ex) {
533 40435 jjdelcerro
            throw ex;
534 44977 jjdelcerro
        } finally {
535
            // This is the feature set we dont want to lose it
536
            // featureSet.dispose();
537 40435 jjdelcerro
        }
538
    }
539
540 43660 jjdelcerro
    private void loadDataFromFeatureSet(final Page page,
541 44977 jjdelcerro
            final int valuesPosition, FeatureSet set, long initialIndex,
542
            final long howMany, final FeatureSelection selectedFeaturesToSkip)
543
            throws DataException {
544 40435 jjdelcerro
545
        try {
546 44840 jjdelcerro
            final MutableBoolean errorReported = new MutableBoolean(false);
547 40435 jjdelcerro
            set.accept(new Visitor() {
548
                private int i = valuesPosition;
549
550 43660 jjdelcerro
                @Override
551 40435 jjdelcerro
                public void visit(Object obj) throws VisitCanceledException,
552 44977 jjdelcerro
                        BaseException {
553 40435 jjdelcerro
                    if (i >= valuesPosition + howMany) {
554
                        throw new VisitCanceledException();
555
                    }
556
                    Feature current = (Feature) obj;
557
                    // Add the current Feature only if we don't skip selected
558
                    // features or the feature is not selected
559
                    if (selectedFeaturesToSkip == null
560 44977 jjdelcerro
                            || !selectedFeaturesToSkip.isSelected(current)) {
561 41630 jjdelcerro
                        try {
562 44977 jjdelcerro
                            page.setFeature(i, current.getCopy());
563 41630 jjdelcerro
                            i++;
564 44977 jjdelcerro
                        } catch (Exception ex) {
565 41630 jjdelcerro
                            // Aqui no deberia petar, pero...
566
                            // me he encontrado un caso que tenia una referencia a
567 41819 fdiaz
                            // una feature seleccionada que ya no existia. No se como
568 41630 jjdelcerro
                            // habia pasado, se habia quedado de antes guardada en el
569
                            // proyecto pero la feature ya no existia, y eso hacia que
570
                            // petase al intentar leer de disco la feature a partir
571
                            // de una referencia no valida.
572 44977 jjdelcerro
                            if (!errorReported.booleanValue()) {
573
                                // Solo sacamos un error por pagina de datos.
574
                                LOG.warn("Problemas recuperando feature.", ex);
575
                                errorReported.setTrue();
576 44840 jjdelcerro
                            }
577 41630 jjdelcerro
                        }
578 40435 jjdelcerro
                    }
579
                }
580 43358 jjdelcerro
            }, initialIndex, howMany);
581 44977 jjdelcerro
        } catch (VisitCanceledException ex) {
582 43358 jjdelcerro
            // Do nothing
583 40435 jjdelcerro
        } catch (BaseException e) {
584
            if (e instanceof DataException) {
585
                throw ((DataException) e);
586
            } else {
587 44977 jjdelcerro
                LOG.warn("Error loading the data starting at position {}", initialIndex, e);
588 40435 jjdelcerro
            }
589
        }
590
    }
591
592 44977 jjdelcerro
    @Override
593 40435 jjdelcerro
    public void delete(Feature feature) throws BaseException {
594
        featureStore.delete(feature);
595
        /*
596
         * Force re-creation of feature set
597
         */
598
        this.getFeatureSet(true);
599
600
        reloadCurrentPage();
601
    }
602
603 44977 jjdelcerro
    @Override
604 40435 jjdelcerro
    public void insert(EditableFeature feature) throws BaseException {
605 44977 jjdelcerro
        featureStore.insert(feature);
606 40435 jjdelcerro
        /*
607
         * Force re-creation of feature set
608
         */
609
        this.getFeatureSet(true);
610
611
        reloadCurrentPage();
612
    }
613 44977 jjdelcerro
614
    @Override
615 44488 jjdelcerro
    public boolean isEmpty() {
616
        try {
617
            return getFeatureSet(false).isEmpty();
618
        } catch (ConcurrentDataModificationException ex) {
619
            LOG.warn("ConcurrentDataModification error asking about the emptiness of the list. Retrying reloading data.");
620
            try {
621
                reload();
622
            } catch (BaseException e) {
623
                LOG.warn("Error reloading data.", e);
624
                throw new RuntimeException(e);
625
            }
626
            try {
627
                return getFeatureSet(false).isEmpty();
628 45425 jjdelcerro
            } catch (RuntimeException e) {
629
                throw  e;
630
            } catch (Exception e) {
631 44977 jjdelcerro
                LOG.warn("Error asking about the emptiness of the list after reloading data.", e);
632 44488 jjdelcerro
                throw new RuntimeException(e);
633
            }
634 45425 jjdelcerro
        } catch (Exception ex) {
635 44977 jjdelcerro
            throw new RuntimeException(ex);
636 44488 jjdelcerro
        }
637
    }
638 40435 jjdelcerro
639 44977 jjdelcerro
    @Override
640 40435 jjdelcerro
    public void update(EditableFeature feature) throws BaseException {
641 44977 jjdelcerro
        featureStore.update(feature);
642 40435 jjdelcerro
        /*
643
         * Force re-creation of feature set
644
         */
645
        this.getFeatureSet(true);
646
647
        reloadCurrentPage();
648
    }
649
650 44977 jjdelcerro
    @Override
651 40435 jjdelcerro
    public FeatureType getFeatureType() {
652 41819 fdiaz
653 40435 jjdelcerro
        FeatureType ft = null;
654 41819 fdiaz
655 40435 jjdelcerro
        try {
656
            ft = featureStore.getDefaultFeatureType();
657
        } catch (DataException e) {
658 44977 jjdelcerro
            LOG.warn("Error while getting feature type: "+ e.getMessage(), e);
659 40435 jjdelcerro
        }
660
        return ft;
661
    }
662
663 44977 jjdelcerro
    @Override
664 40435 jjdelcerro
    protected void doDispose() throws BaseException {
665
        if (featSet != null) {
666
            try {
667
                featSet.dispose();
668
            } catch (Exception ex) {
669
                LOG.info("Error while disposing featset.", ex);
670
            }
671
        }
672
    }
673
674 44977 jjdelcerro
    @Override
675 40435 jjdelcerro
    public DynObject[] getCurrentPageDynObjects() {
676 44977 jjdelcerro
        Feature[] theFeatures = getCurrentPageFeatures();
677
        DynObject[] dynobjects = new DynObject[theFeatures.length];
678 40435 jjdelcerro
        for (int i = 0; i < dynobjects.length; i++) {
679 44977 jjdelcerro
            dynobjects[i] = new DynObjectFeatureFacade(theFeatures[i]);
680 40435 jjdelcerro
        }
681
        return dynobjects;
682
    }
683
684 44253 jjdelcerro
    @Override
685 40435 jjdelcerro
    public DynObject getDynObjectAt(long index) throws BaseException {
686
        return new DynObjectFeatureFacade(getFeatureAt(index));
687
    }
688
689 44253 jjdelcerro
    @Override
690 41212 jjdelcerro
    public List asList() {
691
        return new FeaturePagingHelperList();
692
    }
693 41819 fdiaz
694 44253 jjdelcerro
    @Override
695 41212 jjdelcerro
    public List asListOfDynObjects() {
696
        return new DynObjectPagingHelperList();
697 41819 fdiaz
    }
698
699 41212 jjdelcerro
    private class FeaturePagingHelperList extends PagingHelperList {
700 44977 jjdelcerro
701 44253 jjdelcerro
        @Override
702 41212 jjdelcerro
        public Object get(int i) {
703 44253 jjdelcerro
            return this.get64(i);
704
        }
705
706
        @Override
707
        public Object get64(long i) {
708 41212 jjdelcerro
            try {
709
                return getFeatureAt(i);
710 44253 jjdelcerro
            } catch (ConcurrentDataModificationException ex) {
711 44977 jjdelcerro
                LOG.warn("ConcurrentDataModification error getting feature " + i + " of the list. Retrying reloading data.");
712 44253 jjdelcerro
                try {
713
                    reload();
714
                } catch (BaseException e) {
715
                    LOG.warn("Error reloading data.", e);
716
                    throw new RuntimeException(e);
717
                }
718
                try {
719
                    return getFeatureAt(i);
720
                } catch (Exception e) {
721 44977 jjdelcerro
                    LOG.warn("Error getting feature " + i + " of the list after reloading data.", e);
722 44253 jjdelcerro
                    throw new RuntimeException(e);
723
                }
724 41212 jjdelcerro
            } catch (BaseException ex) {
725 44977 jjdelcerro
                throw new RuntimeException(ex);
726 41212 jjdelcerro
            }
727
        }
728 44253 jjdelcerro
729
        @Override
730
        public Object set(int i, Object e) {
731
            return super.set(i, e);
732
        }
733
734
        @Override
735
        public Object remove(int i) {
736
            return super.remove(i);
737
        }
738
739
        @Override
740
        public boolean add(Object e) {
741
            return super.add(e);
742
        }
743 41212 jjdelcerro
    }
744 41819 fdiaz
745 41212 jjdelcerro
    private class DynObjectPagingHelperList extends PagingHelperList {
746 44977 jjdelcerro
747 44253 jjdelcerro
        @Override
748 41212 jjdelcerro
        public Object get(int i) {
749 44253 jjdelcerro
            return this.get64(i);
750
        }
751
752
        @Override
753
        public Object get64(long position) {
754 41212 jjdelcerro
            try {
755 44253 jjdelcerro
                return getDynObjectAt(position);
756
            } catch (ConcurrentDataModificationException ex) {
757 44977 jjdelcerro
                LOG.warn("ConcurrentDataModification error getting element " + position + " of the list. Retrying reloading data.");
758 44253 jjdelcerro
                try {
759
                    reload();
760
                } catch (BaseException e) {
761
                    LOG.warn("Error reloading data.", e);
762
                    throw new RuntimeException(e);
763
                }
764
                try {
765
                    return getDynObjectAt(position);
766
                } catch (Exception e) {
767 44977 jjdelcerro
                    LOG.warn("Error getting element " + position + " of the list after reloading data.", e);
768 44253 jjdelcerro
                    throw new RuntimeException(e);
769
                }
770 41212 jjdelcerro
            } catch (BaseException ex) {
771 44977 jjdelcerro
                throw new RuntimeException(ex);
772 41212 jjdelcerro
            }
773
        }
774 42775 jjdelcerro
775 41212 jjdelcerro
    }
776 41819 fdiaz
777 45196 jjdelcerro
    private abstract class PagingHelperList implements List, FacadeOfAFeaturePagingHelper, UnmodifiableBasicList, UnmodifiableBasicList64, Disposable {
778 41212 jjdelcerro
779 42775 jjdelcerro
        @Override
780 45196 jjdelcerro
        public void dispose() {
781
            FeaturePagingHelperImpl.this.dispose();
782
        }
783
784
        @Override
785 42775 jjdelcerro
        public FeaturePagingHelper getFeaturePagingHelper() {
786
            return FeaturePagingHelperImpl.this;
787
        }
788 44253 jjdelcerro
789
        @Override
790
        public String toString() {
791
            return String.format("..(%d %ss)...", this.size(), featureStore.getName());
792
        }
793 44977 jjdelcerro
794 44253 jjdelcerro
        @Override
795
        public long size64() {
796 45195 omartinez
            FeatureSet fset = null;
797 41212 jjdelcerro
            try {
798 45195 omartinez
                fset = getFeatureSet(false);
799
                return fset.getSize();
800 44253 jjdelcerro
            } catch (ConcurrentDataModificationException ex) {
801
                LOG.warn("ConcurrentDataModification error asking the size of the list. Retrying reloading data.");
802
                try {
803
                    reload();
804
                } catch (BaseException e) {
805
                    LOG.warn("Error reloading data.", e);
806
                    throw new RuntimeException(e);
807
                }
808
                try {
809 45195 omartinez
                    fset = getFeatureSet(false);
810
                    return fset.getSize();
811 44253 jjdelcerro
                } catch (DataException e) {
812 44977 jjdelcerro
                    LOG.warn("Error asking the size of the list after reloading data.", e);
813 44253 jjdelcerro
                    throw new RuntimeException(e);
814
                }
815 41212 jjdelcerro
            } catch (DataException ex) {
816 44977 jjdelcerro
                throw new RuntimeException(ex);
817 41212 jjdelcerro
            }
818
        }
819
820 44253 jjdelcerro
        @Override
821
        public int size() {
822
            long sz = this.size64();
823 44977 jjdelcerro
            if (sz > Integer.MAX_VALUE) {
824 44253 jjdelcerro
                sz = Integer.MAX_VALUE;
825
            }
826
            return (int) sz;
827
        }
828
829
        @Override
830 41212 jjdelcerro
        public boolean isEmpty() {
831
            try {
832
                return getFeatureSet(false).isEmpty();
833 41819 fdiaz
            } catch (ConcurrentDataModificationException ex) {
834 44253 jjdelcerro
                LOG.warn("ConcurrentDataModification error asking about the emptiness of the list. Retrying reloading data.");
835 41819 fdiaz
                try {
836
                    reload();
837
                } catch (BaseException e) {
838
                    LOG.warn("Error reloading data.", e);
839
                    throw new RuntimeException(e);
840
                }
841
                try {
842
                    return getFeatureSet(false).isEmpty();
843 45425 jjdelcerro
                } catch (RuntimeException e) {
844
                    throw  e;
845
                } catch (Exception e) {
846 44977 jjdelcerro
                    LOG.warn("Error asking about the emptiness of the list after reloading data.", e);
847 41819 fdiaz
                    throw new RuntimeException(e);
848
                }
849 45425 jjdelcerro
            } catch (RuntimeException ex) {
850
                throw  ex;
851
            } catch (Exception ex) {
852 44977 jjdelcerro
                throw new RuntimeException(ex);
853 41212 jjdelcerro
            }
854
        }
855
856 44253 jjdelcerro
        @Override
857 41212 jjdelcerro
        public Iterator iterator() {
858
            try {
859
                return getFeatureSet(false).fastIterator();
860 44253 jjdelcerro
            } catch (ConcurrentDataModificationException ex) {
861
                LOG.warn("ConcurrentDataModification error getting iterator of the list. Retrying reloading data.");
862
                try {
863
                    reload();
864
                } catch (BaseException e) {
865
                    LOG.warn("Error reloading data.", e);
866
                    throw new RuntimeException(e);
867
                }
868
                try {
869
                    return getFeatureSet(false).fastIterator();
870
                } catch (DataException e) {
871 44977 jjdelcerro
                    LOG.warn("Error getting iterator of the list after reloading data.", e);
872 44253 jjdelcerro
                    throw new RuntimeException(e);
873
                }
874 41212 jjdelcerro
            } catch (DataException ex) {
875 44977 jjdelcerro
                throw new RuntimeException(ex);
876 41212 jjdelcerro
            }
877
        }
878
879 44253 jjdelcerro
        @Override
880 41212 jjdelcerro
        public boolean contains(Object o) {
881
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
882
        }
883
884 44253 jjdelcerro
        @Override
885 41212 jjdelcerro
        public Object[] toArray() {
886
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
887
        }
888
889 44253 jjdelcerro
        @Override
890 41212 jjdelcerro
        public Object[] toArray(Object[] ts) {
891
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
892
        }
893
894 44253 jjdelcerro
        @Override
895 41212 jjdelcerro
        public boolean add(Object e) {
896
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
897
        }
898
899 44253 jjdelcerro
        @Override
900 41212 jjdelcerro
        public boolean remove(Object o) {
901
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
902
        }
903
904 44253 jjdelcerro
        @Override
905 41212 jjdelcerro
        public boolean containsAll(Collection clctn) {
906
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
907
        }
908
909 44253 jjdelcerro
        @Override
910 41212 jjdelcerro
        public boolean addAll(Collection clctn) {
911
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
912
        }
913
914 44253 jjdelcerro
        @Override
915 41212 jjdelcerro
        public boolean addAll(int i, Collection clctn) {
916
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
917
        }
918
919 44253 jjdelcerro
        @Override
920 41212 jjdelcerro
        public boolean removeAll(Collection clctn) {
921
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
922
        }
923
924 44253 jjdelcerro
        @Override
925 41212 jjdelcerro
        public boolean retainAll(Collection clctn) {
926
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
927
        }
928
929 44253 jjdelcerro
        @Override
930 41212 jjdelcerro
        public void clear() {
931
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
932
        }
933
934 44253 jjdelcerro
        @Override
935 41212 jjdelcerro
        public Object set(int i, Object e) {
936
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
937
        }
938
939 44253 jjdelcerro
        @Override
940 41212 jjdelcerro
        public void add(int i, Object e) {
941
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
942
        }
943
944 44253 jjdelcerro
        @Override
945 41212 jjdelcerro
        public Object remove(int i) {
946
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
947
        }
948
949 44253 jjdelcerro
        @Override
950 41212 jjdelcerro
        public int indexOf(Object o) {
951
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
952
        }
953
954 44253 jjdelcerro
        @Override
955 41212 jjdelcerro
        public int lastIndexOf(Object o) {
956
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
957
        }
958
959 44253 jjdelcerro
        @Override
960 41212 jjdelcerro
        public ListIterator listIterator() {
961
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
962
        }
963
964 44253 jjdelcerro
        @Override
965 41212 jjdelcerro
        public ListIterator listIterator(int i) {
966
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
967
        }
968
969 44253 jjdelcerro
        @Override
970 41212 jjdelcerro
        public List subList(int i, int i1) {
971
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
972
        }
973 41819 fdiaz
974 44253 jjdelcerro
        @Override
975
        public List toList() {
976
            return this;
977
        }
978
979 41212 jjdelcerro
    }
980 45425 jjdelcerro
981
    @Override
982
    public long size64() {
983
        return this.getTotalSize();
984
    }
985
986
    @Override
987
    public Feature get64(long position) {
988
        try {
989
            return this.getFeatureAt(position);
990
        } catch (BaseException ex) {
991
            throw new RuntimeException(ex);
992
        }
993
    }
994
995
    @Override
996
    public Iterator<Feature> iterator() {
997
        try {
998
            return getFeatureSet(false).fastIterator();
999
        } catch (Exception ex) {
1000
            throw new RuntimeException(ex);
1001
        }
1002
    }
1003
1004 40435 jjdelcerro
}