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

History | View | Annotate | Download (16.8 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
/*
25
 * AUTHORS (In addition to CIT):
26
 * 2008 {DiSiD Technologies}  {Create a JTable TableModel for a FeatureCollection}
27
 */
28
package org.gvsig.fmap.dal.feature.paging.impl;
29

    
30
import org.slf4j.Logger;
31
import org.slf4j.LoggerFactory;
32

    
33
import org.gvsig.fmap.dal.exception.DataException;
34
import org.gvsig.fmap.dal.feature.EditableFeature;
35
import org.gvsig.fmap.dal.feature.Feature;
36
import org.gvsig.fmap.dal.feature.FeatureQuery;
37
import org.gvsig.fmap.dal.feature.FeatureSelection;
38
import org.gvsig.fmap.dal.feature.FeatureSet;
39
import org.gvsig.fmap.dal.feature.FeatureStore;
40
import org.gvsig.fmap.dal.feature.FeatureType;
41
import org.gvsig.fmap.dal.feature.exception.FeatureIndexException;
42
import org.gvsig.fmap.dal.feature.impl.featureset.DynObjectFeatureFacade;
43
import org.gvsig.fmap.dal.feature.paging.FeaturePagingHelper;
44
import org.gvsig.tools.dynobject.DynObject;
45
import org.gvsig.tools.dynobject.DynObjectSet;
46
import org.gvsig.tools.dynobject.impl.DefaultDynObjectPagingHelper;
47
import org.gvsig.tools.exception.BaseException;
48
import org.gvsig.tools.visitor.VisitCanceledException;
49
import org.gvsig.tools.visitor.Visitor;
50

    
51
/**
52
 * Helper class to access the values of a FeatureCollection by position. Handles
53
 * pagination automatically to avoid filling the memory in case of big
54
 * collections.
55
 * 
56
 * TODO: evaluate if its more convenient to read values in the background when
57
 * the returned value is near the end of the page, instead of loading a page on
58
 * demand.
59
 * 
60
 * @author gvSIG Team
61
 */
62
public class FeaturePagingHelperImpl extends DefaultDynObjectPagingHelper
63
    implements FeaturePagingHelper {
64

    
65
    private static final Logger LOG = LoggerFactory
66
        .getLogger(FeaturePagingHelperImpl.class);
67

    
68
    private FeatureQuery query;
69

    
70
    private FeatureStore featureStore;
71

    
72
    /** If the selected Features must be returned as the first ones. **/
73
    private boolean selectionUp = false;
74

    
75
    private FeatureSet featSet = null;
76
    private FeatureSelection initialSelection = null;
77

    
78
    private Feature[] features = null;
79

    
80
    /**
81
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
82
     * 
83
     * @param featureStore
84
     *            to extract data from
85
     * @throws DataException
86
     *             if there is an error initializing the helper
87
     */
88
    public FeaturePagingHelperImpl(FeatureStore featureStore)
89
        throws BaseException {
90
        this(featureStore, DEFAULT_PAGE_SIZE);
91
    }
92

    
93
    /**
94
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
95
     * 
96
     * @param featureStore
97
     *            to extract data from
98
     * @param pageSize
99
     *            the number of elements per page data
100
     * @throws DataException
101
     *             if there is an error initializing the helper
102
     */
103
    public FeaturePagingHelperImpl(FeatureStore featureStore, int pageSize)
104
        throws BaseException {
105
        this(featureStore, null, pageSize);
106
    }
107

    
108
    /**
109
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
110
     * 
111
     * @param featureStore
112
     *            to extract data from
113
     * @throws DataException
114
     *             if there is an error initializing the helper
115
     */
116
    public FeaturePagingHelperImpl(FeatureStore featureStore,
117
        FeatureQuery featureQuery) throws BaseException {
118
        this(featureStore, featureQuery, DEFAULT_PAGE_SIZE);
119
    }
120

    
121
    /**
122
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
123
     * 
124
     * @param featureSet
125
     *            to extract data from
126
     * @param pageSize
127
     *            the number of elements per page data
128
     * @throws DataException
129
     *             if there is an error initializing the helper
130
     */
131
    public FeaturePagingHelperImpl(FeatureStore featureStore,
132
        FeatureQuery featureQuery, int pageSize) throws BaseException {
133
        super();
134
        FeatureQuery query = featureQuery;
135
        if (featureQuery == null) {
136
            query = featureStore.createFeatureQuery();
137
            query.setFeatureType(featureStore.getDefaultFeatureType());
138
        }
139

    
140
        this.featureStore = featureStore;
141
        this.query = query;
142
        this.query.setPageSize(pageSize);
143

    
144
        if (LOG.isDebugEnabled()) {
145
            LOG.debug("FeaturePagingHelperImpl created with {} pages, "
146
                + "and a page size of {}", new Long(getCalculator()
147
                .getNumPages()), new Integer(pageSize));
148
        }
149
        
150
        setDefaultCalculator(new Sizeable() {
151
            public long getSize() {
152
                    FeatureSet featureSet = getFeatureSet(false);
153
                try {
154
                                        return featureSet.getSize();
155
                } catch (BaseException e) {
156
                    LOG.error("Error getting the size of the FeatureSet: "
157
                        + featureSet, e);
158
                    return 0l;
159
                }
160
            }
161
        }, pageSize);
162
    }
163

    
164
    /**
165
     * @return the selectionUp status
166
     */
167
    protected boolean isSelectionUp() {
168
        return selectionUp;
169
    }
170

    
171
    public void setSelectionUp(boolean selectionUp) {
172
        this.selectionUp = selectionUp;
173
        try {
174
            if (selectionUp) {
175
                initialSelection =
176
                    (FeatureSelection) getFeatureStore().getFeatureSelection()
177
                        .clone();
178
                setCalculator(new OneSubsetOneSetPagingCalculator(
179
                    new FeatureSetSizeableDelegate(initialSelection),
180
                    new FeatureSetSizeableDelegate(getFeatureSet(false)),
181
                    getMaxPageSize()));
182
            } else {
183
                if (initialSelection != null) {
184
                    initialSelection.dispose();
185
                    initialSelection = null;
186
                }
187
                setDefaultCalculator(new FeatureSetSizeableDelegate(
188
                    getFeatureSet(false)), getMaxPageSize());
189
            }
190
        } catch (BaseException e) {
191
            LOG.error("Error setting the selection up setting to: "
192
                + selectionUp, e);
193
        } catch (CloneNotSupportedException e) {
194
            LOG.error("Error cloning the selection "
195
                + "while setting the selection up", e);
196
        }
197
    }
198

    
199
    public Feature getFeatureAt(long index) throws BaseException {
200
        // Check if we have currently loaded the viewed page data,
201
        // or we need to load a new one
202
        long pageForIndex = (long) Math.floor(index / getMaxPageSize());
203

    
204
        if (pageForIndex != getCurrentPage()) {
205
            setCurrentPage(pageForIndex);
206
        }
207

    
208
        long positionForIndex = index - (getCurrentPage() * getMaxPageSize());
209

    
210
        if (positionForIndex >= features.length) {
211
            throw new FeatureIndexException(
212
                new IndexOutOfBoundsException("positionForIndex too big: "
213
                    + positionForIndex));
214
        } else {
215
            return features[(int) positionForIndex];
216
        }
217
        
218
    }
219

    
220
    public Feature[] getCurrentPageFeatures() {
221
        return features;
222
    }
223

    
224
    /**
225
     * Gets the feature set.
226
     * The boolean tells whether we must create the featureset
227
     * again (for example perhaps we need it after a feature
228
     * has been added/removed)
229
     */
230
    private FeatureSet getFeatureSet(boolean reset) {
231
        
232
        if (featSet == null || reset) {
233
            
234
            if (featSet != null) {
235
                try {
236
                    featSet.dispose();
237
                } catch (Exception ex) {
238
                    LOG.info("Error while disposing featset.", ex);
239
                }
240
            }
241
            
242
            try {
243
                FeatureStore featureStore = getFeatureStore();          
244
                synchronized (featureStore) {
245
                    featSet = featureStore.getFeatureSet(getFeatureQuery());               
246
                }
247
            } catch (DataException e) {
248
                throw new RuntimeException("Error getting a feature set with the query " + getFeatureQuery());
249
            }
250
        }
251
        return featSet;
252
    }
253
    
254
    public DynObjectSet getDynObjectSet() {
255
            return getFeatureSet(false).getDynObjectSet();
256
    }
257

    
258
    public void reloadCurrentPage() throws BaseException {
259
        
260
        boolean sel_up = this.isSelectionUp();
261

    
262
        setSelectionUp(false);
263
        if (getCalculator().getCurrentPage() > -1) {
264
            loadCurrentPageData();
265
        }
266
        
267
        if (sel_up) {
268
            setSelectionUp(true);
269
        }
270
    }
271

    
272
    public void reload() throws BaseException {
273
        
274
        /*
275
         * Force re-creation of feature set
276
         */
277
        this.getFeatureSet(true);
278

    
279
        
280
        setDefaultCalculator(new Sizeable() {
281
            public long getSize() {
282
                    FeatureSet featureSet = getFeatureSet(false);
283
                try {
284
                                        return featureSet.getSize();
285
                } catch (BaseException e) {
286
                    LOG.error("Error getting the size of the FeatureSet: "
287
                        + featureSet, e);
288
                    return 0l;
289
                }
290
            }
291
        }, getCalculator().getMaxPageSize());
292
        reloadCurrentPage();
293
    }
294

    
295
    public FeatureStore getFeatureStore() {
296
        return featureStore;
297
    }
298

    
299
    public FeatureQuery getFeatureQuery() {
300
        return query;
301
    }
302

    
303
    /**
304
     * Loads all the Features of the current page.
305
     */
306
    protected void loadCurrentPageData() throws BaseException {
307
        final int currentPageSize = getCalculator().getCurrentPageSize();
308
        final Feature[] values = new Feature[currentPageSize];
309

    
310
        long t1 = 0;
311
        if (LOG.isTraceEnabled()) {
312
            t1 = System.currentTimeMillis();
313
        }
314

    
315
        if (selectionUp) {
316
            loadCurrentPageDataWithSelectionUp(values);
317
        } else {
318
            loadCurrentPageDataNoSelection(values);
319
        }
320

    
321
        if (LOG.isTraceEnabled()) {
322
            long t2 = System.currentTimeMillis();
323
            LOG.trace("Time to load {} features: {} ms", new Integer(
324
                currentPageSize), new Long(t2 - t1));
325
        }
326

    
327
        this.features = values;
328
    }
329
    
330
    private void loadCurrentPageDataWithSelectionUp(final Feature[] values)
331
        throws BaseException {
332
        FeatureSelection selection = initialSelection;
333

    
334
        FeatureSet set = getFeatureSet(false);
335
        try {
336
                OneSubsetOneSetPagingCalculator twoSetsCalculator = null;
337
                if (getCalculator() instanceof OneSubsetOneSetPagingCalculator) {
338
                    twoSetsCalculator =
339
                        (OneSubsetOneSetPagingCalculator) getCalculator();
340
                } else {
341
                    twoSetsCalculator =
342
                        new OneSubsetOneSetPagingCalculator(
343
                            new FeatureSetSizeableDelegate(selection),
344
                            new FeatureSetSizeableDelegate(set),
345
                            getMaxPageSize(), getCalculator().getCurrentPage());
346
                    setCalculator(twoSetsCalculator);
347
                }
348
        
349
                // First load values from the selection, if the current page has
350
                // elements from it
351
                if (twoSetsCalculator.hasCurrentPageAnyValuesInFirstSet()) {
352
                    loadDataFromFeatureSet(values, 0, selection,
353
                        twoSetsCalculator.getFirstSetInitialIndex(),
354
                        twoSetsCalculator.getFirstSetHowMany(), null);
355
                }
356
                // Next, load values from the FeatureSet if the current page has values
357
                // from it
358
                if (twoSetsCalculator.hasCurrentPageAnyValuesInSecondSet()) {
359
                    loadDataFromFeatureSet(
360
                        values,
361
                        // The cast will work as that size will be <= maxpagesize,
362
                        // which is an int
363
                        (int) twoSetsCalculator.getFirstSetHowMany(), set,
364
                        twoSetsCalculator.getSecondSetInitialIndex(),
365
                        twoSetsCalculator.getSecondSetHowMany(), selection);
366
                }
367
        } finally {
368
            /*
369
             * This is the feature set
370
             * we dont want to lose it
371
             */
372
                // set.dispose();
373
        }
374
    }
375

    
376
    private void loadCurrentPageDataNoSelection(final Feature[] values)
377
        throws BaseException {
378

    
379
        long firstPosition = getCalculator().getInitialIndex();
380

    
381
        if (LOG.isDebugEnabled()) {
382
            LOG.debug("Loading {} Features starting at position {}",
383
                new Integer(getCalculator().getCurrentPageSize()), new Long(
384
                    firstPosition));
385
        }
386

    
387
        FeatureSet featureSet = getFeatureSet(false);
388
        try {
389
                loadDataFromFeatureSet(values, 0, featureSet, firstPosition,
390
                                getCalculator().getCurrentPageSize(), null);
391
        } catch(DataException ex) {
392
            throw ex;
393
            // } finally {
394
                // featureSet.dispose();
395
        }
396
        
397
    }
398

    
399
    private void loadDataFromFeatureSet(final Feature[] values,
400
        final int valuesPosition, FeatureSet set, long initialIndex,
401
        final long howMany, final FeatureSelection selectedFeaturesToSkip)
402
        throws DataException {
403

    
404
        try {
405
            set.accept(new Visitor() {
406

    
407
                private int i = valuesPosition;
408

    
409
                public void visit(Object obj) throws VisitCanceledException,
410
                    BaseException {
411
                    if (i >= valuesPosition + howMany) {
412
                        throw new VisitCanceledException();
413
                    }
414
                    Feature current = (Feature) obj;
415
                    // Add the current Feature only if we don't skip selected
416
                    // features or the feature is not selected
417
                    if (selectedFeaturesToSkip == null
418
                        || !selectedFeaturesToSkip.isSelected(current)) {
419
                        values[i] = current.getCopy();
420
                        i++;
421
                    }
422
                }
423
            }, initialIndex);
424
        } catch (BaseException e) {
425
            if (e instanceof DataException) {
426
                throw ((DataException) e);
427
            } else {
428
                LOG.error("Error loading the data starting at position {}",
429
                    new Long(initialIndex), e);
430
            }
431
        }
432
    }
433

    
434
    public void delete(Feature feature) throws BaseException {
435
        featureStore.delete(feature);
436
        /*
437
         * Force re-creation of feature set
438
         */
439
        this.getFeatureSet(true);
440

    
441
        reloadCurrentPage();
442
    }
443

    
444
    public void insert(EditableFeature feature) throws BaseException {
445
            featureStore.insert(feature);
446
        /*
447
         * Force re-creation of feature set
448
         */
449
        this.getFeatureSet(true);
450

    
451
        reloadCurrentPage();
452
    }
453

    
454
    public void update(EditableFeature feature) throws BaseException {
455
            featureStore.update(feature);
456
        /*
457
         * Force re-creation of feature set
458
         */
459
        this.getFeatureSet(true);
460

    
461
        reloadCurrentPage();
462
    }
463

    
464
    public FeatureType getFeatureType() {
465
        
466
        FeatureType ft = null;
467
        
468
        try {
469
            ft = featureStore.getDefaultFeatureType();
470
        } catch (DataException e) {
471
            LOG.error("Error while getting feature type: " +
472
                e.getMessage(), e);
473
        }
474
        return ft;
475
        
476
        /*
477
         * 
478
        FeatureSet featureSet = getFeatureSet();
479
        try {
480
            return featureSet.getDefaultFeatureType();
481
        } finally {
482
            featureSet.dispose();
483
        }
484
        */
485

    
486
        
487
    }
488

    
489
    protected void doDispose() throws BaseException {
490
        initialSelection.dispose();
491
        if (featSet != null) {
492
            try {
493
                featSet.dispose();
494
            } catch (Exception ex) {
495
                LOG.info("Error while disposing featset.", ex);
496
            }
497
        }
498
    }
499

    
500
    public DynObject[] getCurrentPageDynObjects() {
501
        Feature[] features = getCurrentPageFeatures();
502
        DynObject[] dynobjects = new DynObject[features.length];
503
        for (int i = 0; i < dynobjects.length; i++) {
504
            dynobjects[i] = new DynObjectFeatureFacade(features[i]);
505
        }
506
        return dynobjects;
507
    }
508

    
509
    public DynObject getDynObjectAt(long index) throws BaseException {
510
        return new DynObjectFeatureFacade(getFeatureAt(index));
511
    }
512

    
513
}