Statistics
| Revision:

svn-gvsig-desktop / branches / v2_0_0_prep / libraries / libFMap_dal / src / org / gvsig / fmap / dal / feature / paging / impl / FeaturePagingHelperImpl.java @ 38417

History | View | Annotate | Download (14.4 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
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 2
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
 */
22

    
23
/*
24
 * AUTHORS (In addition to CIT):
25
 * 2008 {DiSiD Technologies}  {Create a JTable TableModel for a FeatureCollection}
26
 */
27
package org.gvsig.fmap.dal.feature.paging.impl;
28

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

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

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

    
63
    private static final Logger LOG = LoggerFactory
64
        .getLogger(FeaturePagingHelperImpl.class);
65

    
66
    private FeatureQuery query;
67

    
68
    private FeatureStore featureStore;
69

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

    
73
    private FeatureSelection initialSelection = null;
74

    
75
    private Feature[] features = null;
76

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

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

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

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

    
137
        this.featureStore = featureStore;
138
        this.query = query;
139
        this.query.setPageSize(pageSize);
140

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

    
161
    /**
162
     * @return the selectionUp status
163
     */
164
    protected boolean isSelectionUp() {
165
        return selectionUp;
166
    }
167

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

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

    
201
        if (pageForIndex != getCurrentPage()) {
202
            setCurrentPage(pageForIndex);
203
        }
204

    
205
        long positionForIndex = index - (getCurrentPage() * getMaxPageSize());
206

    
207
        return features[(int) positionForIndex];
208
    }
209

    
210
    public Feature[] getCurrentPageFeatures() {
211
        return features;
212
    }
213

    
214
    private FeatureSet getFeatureSet() {
215
        try {
216
                FeatureStore featureStore = getFeatureStore();                
217
                synchronized (featureStore) {
218
                        return featureStore.getFeatureSet(getFeatureQuery());                                
219
                        }
220
                } catch (DataException e) {
221
                        throw new RuntimeException("Error getting a feature set with the query " + getFeatureQuery());
222
                }
223
    }
224
    
225
    public DynObjectSet getDynObjectSet() {
226
            return getFeatureSet().getDynObjectSet();
227
    }
228

    
229
    public void reloadCurrentPage() throws BaseException {
230
        setSelectionUp(false);
231
        if (getCalculator().getCurrentPage() > -1) {
232
            loadCurrentPageData();
233
        }
234
    }
235

    
236
    public void reload() throws BaseException {
237
        setDefaultCalculator(new Sizeable() {
238
            public long getSize() {
239
                    FeatureSet featureSet = getFeatureSet();
240
                try {
241
                                        return featureSet.getSize();
242
                } catch (BaseException e) {
243
                    LOG.error("Error getting the size of the FeatureSet: "
244
                        + featureSet, e);
245
                    return 0l;
246
                }
247
            }
248
        }, getCalculator().getMaxPageSize());
249
        reloadCurrentPage();
250
    }
251

    
252
    public FeatureStore getFeatureStore() {
253
        return featureStore;
254
    }
255

    
256
    public FeatureQuery getFeatureQuery() {
257
        return query;
258
    }
259

    
260
    /**
261
     * Loads all the Features of the current page.
262
     */
263
    protected void loadCurrentPageData() throws BaseException {
264
        final int currentPageSize = getCalculator().getCurrentPageSize();
265
        final Feature[] values = new Feature[currentPageSize];
266

    
267
        long t1 = 0;
268
        if (LOG.isTraceEnabled()) {
269
            t1 = System.currentTimeMillis();
270
        }
271

    
272
        if (selectionUp) {
273
            loadCurrentPageDataWithSelectionUp(values);
274
        } else {
275
            loadCurrentPageDataNoSelection(values);
276
        }
277

    
278
        if (LOG.isTraceEnabled()) {
279
            long t2 = System.currentTimeMillis();
280
            LOG.trace("Time to load {} features: {} ms", new Integer(
281
                currentPageSize), new Long(t2 - t1));
282
        }
283

    
284
        this.features = values;
285
    }
286

    
287
    private void loadCurrentPageDataWithSelectionUp(final Feature[] values)
288
        throws BaseException {
289
        FeatureSelection selection = initialSelection;
290

    
291
        FeatureSet set = getFeatureSet();
292
        try {
293
                OneSubsetOneSetPagingCalculator twoSetsCalculator = null;
294
                if (getCalculator() instanceof OneSubsetOneSetPagingCalculator) {
295
                    twoSetsCalculator =
296
                        (OneSubsetOneSetPagingCalculator) getCalculator();
297
                } else {
298
                    twoSetsCalculator =
299
                        new OneSubsetOneSetPagingCalculator(
300
                            new FeatureSetSizeableDelegate(selection),
301
                            new FeatureSetSizeableDelegate(set),
302
                            getMaxPageSize(), getCalculator().getCurrentPage());
303
                    setCalculator(twoSetsCalculator);
304
                }
305
        
306
                // First load values from the selection, if the current page has
307
                // elements from it
308
                if (twoSetsCalculator.hasCurrentPageAnyValuesInFirstSet()) {
309
                    loadDataFromFeatureSet(values, 0, selection,
310
                        twoSetsCalculator.getFirstSetInitialIndex(),
311
                        twoSetsCalculator.getFirstSetHowMany(), null);
312
                }
313
                // Next, load values from the FeatureSet if the current page has values
314
                // from it
315
                if (twoSetsCalculator.hasCurrentPageAnyValuesInSecondSet()) {
316
                    loadDataFromFeatureSet(
317
                        values,
318
                        // The cast will work as that size will be <= maxpagesize,
319
                        // which is an int
320
                        (int) twoSetsCalculator.getFirstSetHowMany(), set,
321
                        twoSetsCalculator.getSecondSetInitialIndex(),
322
                        twoSetsCalculator.getSecondSetHowMany(), selection);
323
                }
324
        } finally {
325
                set.dispose();
326
        }
327
    }
328

    
329
    private void loadCurrentPageDataNoSelection(final Feature[] values)
330
        throws BaseException {
331

    
332
        long firstPosition = getCalculator().getInitialIndex();
333

    
334
        if (LOG.isDebugEnabled()) {
335
            LOG.debug("Loading {} Features starting at position {}",
336
                new Integer(getCalculator().getCurrentPageSize()), new Long(
337
                    firstPosition));
338
        }
339

    
340
        FeatureSet featureSet = getFeatureSet();
341
        try {
342
                loadDataFromFeatureSet(values, 0, featureSet, firstPosition,
343
                                getCalculator().getCurrentPageSize(), null);
344
        } finally {
345
                featureSet.dispose();
346
        }
347
        
348
    }
349

    
350
    private void loadDataFromFeatureSet(final Feature[] values,
351
        final int valuesPosition, FeatureSet set, long initialIndex,
352
        final long howMany, final FeatureSelection selectedFeaturesToSkip)
353
        throws DataException {
354

    
355
        try {
356
            set.accept(new Visitor() {
357

    
358
                private int i = valuesPosition;
359

    
360
                public void visit(Object obj) throws VisitCanceledException,
361
                    BaseException {
362
                    if (i >= valuesPosition + howMany) {
363
                        throw new VisitCanceledException();
364
                    }
365
                    Feature current = (Feature) obj;
366
                    // Add the current Feature only if we don't skip selected
367
                    // features or the feature is not selected
368
                    if (selectedFeaturesToSkip == null
369
                        || !selectedFeaturesToSkip.isSelected(current)) {
370
                        values[i] = current.getCopy();
371
                        i++;
372
                    }
373
                }
374
            }, initialIndex);
375
        } catch (BaseException e) {
376
            if (e instanceof DataException) {
377
                throw ((DataException) e);
378
            } else {
379
                LOG.error("Error loading the data starting at position {}",
380
                    new Long(initialIndex), e);
381
            }
382
        }
383
    }
384

    
385
    public void delete(Feature feature) throws BaseException {
386
        featureStore.delete(feature);
387
        reloadCurrentPage();
388
    }
389

    
390
    public void insert(EditableFeature feature) throws BaseException {
391
            featureStore.insert(feature);
392
        reloadCurrentPage();
393
    }
394

    
395
    public void update(EditableFeature feature) throws BaseException {
396
            featureStore.update(feature);
397
        reloadCurrentPage();
398
    }
399

    
400
    public FeatureType getFeatureType() {
401
        FeatureSet featureSet = getFeatureSet();
402
        try {
403
                return featureSet.getDefaultFeatureType();
404
        } finally {
405
                featureSet.dispose();
406
        }
407
    }
408

    
409
    protected void doDispose() throws BaseException {
410
        initialSelection.dispose();
411
    }
412

    
413
    public DynObject[] getCurrentPageDynObjects() {
414
        Feature[] features = getCurrentPageFeatures();
415
        DynObject[] dynobjects = new DynObject[features.length];
416
        for (int i = 0; i < dynobjects.length; i++) {
417
            dynobjects[i] = new DynObjectFeatureFacade(features[i]);
418
        }
419
        return dynobjects;
420
    }
421

    
422
    public DynObject getDynObjectAt(long index) throws BaseException {
423
        return new DynObjectFeatureFacade(getFeatureAt(index));
424
    }
425

    
426
}