Statistics
| Revision:

root / branches / v2_0_0_prep / libraries / libFMap_dal / src / org / gvsig / fmap / dal / feature / paging / impl / FeaturePagingHelperImpl.java @ 37297

History | View | Annotate | Download (13.6 KB)

1 23675 cordinyana
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4 31544 cordinyana
 * of the Valencian Government (CIT)
5 23772 jjdelcerro
 *
6 23675 cordinyana
 * 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 23772 jjdelcerro
 *
11 23675 cordinyana
 * 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 23772 jjdelcerro
 *
16 23675 cordinyana
 * 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 23772 jjdelcerro
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 23675 cordinyana
 * MA  02110-1301, USA.
20 23772 jjdelcerro
 *
21 23675 cordinyana
 */
22
23
/*
24
 * AUTHORS (In addition to CIT):
25
 * 2008 {DiSiD Technologies}  {Create a JTable TableModel for a FeatureCollection}
26
 */
27 33343 cordinyana
package org.gvsig.fmap.dal.feature.paging.impl;
28 23675 cordinyana
29 33385 cordinyana
import org.slf4j.Logger;
30
import org.slf4j.LoggerFactory;
31
32 24505 jmvivo
import org.gvsig.fmap.dal.exception.DataException;
33 27234 jmvivo
import org.gvsig.fmap.dal.feature.EditableFeature;
34
import org.gvsig.fmap.dal.feature.Feature;
35
import org.gvsig.fmap.dal.feature.FeatureQuery;
36 33378 cordinyana
import org.gvsig.fmap.dal.feature.FeatureSelection;
37 27234 jmvivo
import org.gvsig.fmap.dal.feature.FeatureSet;
38
import org.gvsig.fmap.dal.feature.FeatureStore;
39
import org.gvsig.fmap.dal.feature.FeatureType;
40 33657 cordinyana
import org.gvsig.fmap.dal.feature.impl.featureset.DynObjectFeatureFacade;
41 33343 cordinyana
import org.gvsig.fmap.dal.feature.paging.FeaturePagingHelper;
42 33205 cordinyana
import org.gvsig.tools.dynobject.DynObject;
43 33385 cordinyana
import org.gvsig.tools.dynobject.impl.DefaultDynObjectPagingHelper;
44 31110 cordinyana
import org.gvsig.tools.exception.BaseException;
45
import org.gvsig.tools.visitor.VisitCanceledException;
46
import org.gvsig.tools.visitor.Visitor;
47 23675 cordinyana
48
/**
49
 * Helper class to access the values of a FeatureCollection by position. Handles
50
 * pagination automatically to avoid filling the memory in case of big
51
 * collections.
52 31110 cordinyana
 *
53 23930 cordinyana
 * TODO: evaluate if its more convenient to read values in the background when
54
 * the returned value is near the end of the page, instead of loading a page on
55
 * demand.
56 31110 cordinyana
 *
57 33385 cordinyana
 * @author gvSIG Team
58 23675 cordinyana
 */
59 33385 cordinyana
public class FeaturePagingHelperImpl extends DefaultDynObjectPagingHelper
60
    implements FeaturePagingHelper {
61 23675 cordinyana
62 33385 cordinyana
    private static final Logger LOG = LoggerFactory
63
        .getLogger(FeaturePagingHelperImpl.class);
64 23930 cordinyana
65 33385 cordinyana
    private FeatureQuery query;
66 23675 cordinyana
67 33385 cordinyana
    private FeatureSet featureSet;
68 23772 jjdelcerro
69 33385 cordinyana
    private FeatureStore featureStore;
70 23675 cordinyana
71 33385 cordinyana
    /** If the selected Features must be returned as the first ones. **/
72
    private boolean selectionUp = false;
73 23675 cordinyana
74 33385 cordinyana
    private FeatureSelection initialSelection = null;
75 23675 cordinyana
76 33385 cordinyana
    private Feature[] features = null;
77 23675 cordinyana
78 33385 cordinyana
    /**
79
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
80
     *
81
     * @param featureStore
82
     *            to extract data from
83
     * @throws DataException
84
     *             if there is an error initializing the helper
85
     */
86
    public FeaturePagingHelperImpl(FeatureStore featureStore)
87
        throws BaseException {
88
        this(featureStore, DEFAULT_PAGE_SIZE);
89
    }
90 23675 cordinyana
91 33385 cordinyana
    /**
92
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
93
     *
94
     * @param featureStore
95
     *            to extract data from
96
     * @param pageSize
97
     *            the number of elements per page data
98
     * @throws DataException
99
     *             if there is an error initializing the helper
100
     */
101
    public FeaturePagingHelperImpl(FeatureStore featureStore, int pageSize)
102
        throws BaseException {
103
        this(featureStore, null, pageSize);
104
    }
105 23675 cordinyana
106 33385 cordinyana
    /**
107
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
108
     *
109
     * @param featureStore
110
     *            to extract data from
111
     * @throws DataException
112
     *             if there is an error initializing the helper
113
     */
114
    public FeaturePagingHelperImpl(FeatureStore featureStore,
115
        FeatureQuery featureQuery) throws BaseException {
116
        this(featureStore, featureQuery, DEFAULT_PAGE_SIZE);
117
    }
118 23675 cordinyana
119 33385 cordinyana
    /**
120
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
121
     *
122
     * @param featureSet
123
     *            to extract data from
124
     * @param pageSize
125
     *            the number of elements per page data
126
     * @throws DataException
127
     *             if there is an error initializing the helper
128
     */
129
    public FeaturePagingHelperImpl(FeatureStore featureStore,
130
        FeatureQuery featureQuery, int pageSize) throws BaseException {
131
        super();
132
        FeatureQuery query = featureQuery;
133
        if (featureQuery == null) {
134
            query = featureStore.createFeatureQuery();
135
            query.setFeatureType(featureStore.getDefaultFeatureType());
136
        }
137 23675 cordinyana
138 33385 cordinyana
        this.featureStore = featureStore;
139
        this.query = query;
140
        this.query.setPageSize(pageSize);
141
        loadFeatureSet();
142 33378 cordinyana
143 33385 cordinyana
        if (LOG.isDebugEnabled()) {
144
            LOG.debug("FeaturePagingHelperImpl created with {} pages, "
145
                + "and a page size of {}", new Long(getCalculator()
146
                .getNumPages()), new Integer(pageSize));
147
        }
148
    }
149 24023 cordinyana
150 33385 cordinyana
    /**
151
     * @return the selectionUp status
152
     */
153
    protected boolean isSelectionUp() {
154
        return selectionUp;
155
    }
156 33378 cordinyana
157 33385 cordinyana
    public void setSelectionUp(boolean selectionUp) {
158
        this.selectionUp = selectionUp;
159
        try {
160
            if (selectionUp) {
161
                initialSelection =
162
                    (FeatureSelection) getFeatureStore().getFeatureSelection()
163
                        .clone();
164
                setCalculator(new OneSubsetOneSetPagingCalculator(
165
                    new FeatureSetSizeableDelegate(initialSelection),
166
                    new FeatureSetSizeableDelegate(getFeatureSet()),
167
                    getMaxPageSize()));
168
            } else {
169
                if (initialSelection != null) {
170
                    initialSelection.dispose();
171
                    initialSelection = null;
172
                }
173
                setDefaultCalculator(new FeatureSetSizeableDelegate(
174 33657 cordinyana
                    getFeatureSet()), getMaxPageSize());
175 33385 cordinyana
            }
176
        } catch (BaseException e) {
177
            LOG.error("Error setting the selection up setting to: "
178
                + selectionUp, e);
179
        } catch (CloneNotSupportedException e) {
180
            LOG.error("Error cloning the selection "
181
                + "while setting the selection up", e);
182
        }
183
    }
184 23675 cordinyana
185 33385 cordinyana
    public Feature getFeatureAt(long index) throws BaseException {
186
        // Check if we have currently loaded the viewed page data,
187
        // or we need to load a new one
188
        long pageForIndex = (long) Math.floor(index / getMaxPageSize());
189 33378 cordinyana
190 33385 cordinyana
        if (pageForIndex != getCurrentPage()) {
191
            setCurrentPage(pageForIndex);
192
        }
193 33378 cordinyana
194 33385 cordinyana
        long positionForIndex = index - (getCurrentPage() * getMaxPageSize());
195 23675 cordinyana
196 33385 cordinyana
        return features[(int) positionForIndex];
197
    }
198 23675 cordinyana
199 33385 cordinyana
    public Feature[] getCurrentPageFeatures() {
200
        return features;
201
    }
202 23675 cordinyana
203 33385 cordinyana
    public FeatureSet getFeatureSet() {
204
        return featureSet;
205
    }
206 23675 cordinyana
207 33385 cordinyana
    public void reloadCurrentPage() throws BaseException {
208
        setSelectionUp(false);
209
        if (getCalculator().getCurrentPage() > -1) {
210
            loadCurrentPageData();
211
        }
212
    }
213 23675 cordinyana
214 33385 cordinyana
    public void reload() throws BaseException {
215
        loadFeatureSet();
216
        reloadCurrentPage();
217
    }
218 23675 cordinyana
219 33385 cordinyana
    public FeatureStore getFeatureStore() {
220
        return featureStore;
221
    }
222 23675 cordinyana
223 33385 cordinyana
    public FeatureQuery getFeatureQuery() {
224
        return query;
225
    }
226 23772 jjdelcerro
227 33385 cordinyana
    /**
228
     * Loads all the Features of the current page.
229
     */
230
    protected void loadCurrentPageData() throws BaseException {
231
        final int currentPageSize = getCalculator().getCurrentPageSize();
232
        final Feature[] values = new Feature[currentPageSize];
233 23772 jjdelcerro
234 33385 cordinyana
        long t1 = 0;
235
        if (LOG.isTraceEnabled()) {
236
            t1 = System.currentTimeMillis();
237
        }
238 23772 jjdelcerro
239 33385 cordinyana
        if (selectionUp) {
240
            loadCurrentPageDataWithSelectionUp(values);
241
        } else {
242
            loadCurrentPageDataNoSelection(values);
243
        }
244 23675 cordinyana
245 33385 cordinyana
        if (LOG.isTraceEnabled()) {
246
            long t2 = System.currentTimeMillis();
247
            LOG.trace("Time to load {} features: {} ms", new Integer(
248
                currentPageSize), new Long(t2 - t1));
249
        }
250 23772 jjdelcerro
251 33385 cordinyana
        this.features = values;
252
    }
253 23772 jjdelcerro
254 33385 cordinyana
    private void loadCurrentPageDataWithSelectionUp(final Feature[] values)
255
        throws BaseException {
256
        FeatureSelection selection = initialSelection;
257 23675 cordinyana
258 33385 cordinyana
        OneSubsetOneSetPagingCalculator twoSetsCalculator = null;
259
        if (getCalculator() instanceof OneSubsetOneSetPagingCalculator) {
260
            twoSetsCalculator =
261
                (OneSubsetOneSetPagingCalculator) getCalculator();
262
        } else {
263
            twoSetsCalculator =
264
                new OneSubsetOneSetPagingCalculator(
265
                    new FeatureSetSizeableDelegate(selection),
266
                    new FeatureSetSizeableDelegate(getFeatureSet()),
267
                    getMaxPageSize(), getCalculator().getCurrentPage());
268
            setCalculator(twoSetsCalculator);
269
        }
270 23675 cordinyana
271 33385 cordinyana
        // First load values from the selection, if the current page has
272
        // elements from it
273
        if (twoSetsCalculator.hasCurrentPageAnyValuesInFirstSet()) {
274
            loadDataFromFeatureSet(values, 0, selection,
275
                twoSetsCalculator.getFirstSetInitialIndex(),
276
                twoSetsCalculator.getFirstSetHowMany(), null);
277
        }
278
        // Next, load values from the FeatureSet if the current page has values
279
        // from it
280
        if (twoSetsCalculator.hasCurrentPageAnyValuesInSecondSet()) {
281
            loadDataFromFeatureSet(
282
                values,
283
                // The cast will work as that size will be <= maxpagesize,
284
                // which is an int
285
                (int) twoSetsCalculator.getFirstSetHowMany(), getFeatureSet(),
286
                twoSetsCalculator.getSecondSetInitialIndex(),
287
                twoSetsCalculator.getSecondSetHowMany(), selection);
288
        }
289
    }
290 23714 cordinyana
291 33385 cordinyana
    private void loadCurrentPageDataNoSelection(final Feature[] values)
292
        throws DataException {
293 33378 cordinyana
294 33385 cordinyana
        long firstPosition = getCalculator().getInitialIndex();
295 23675 cordinyana
296 33385 cordinyana
        if (LOG.isDebugEnabled()) {
297
            LOG.debug("Loading {} Features starting at position {}",
298
                new Integer(getCalculator().getCurrentPageSize()), new Long(
299
                    firstPosition));
300
        }
301 23675 cordinyana
302 33385 cordinyana
        loadDataFromFeatureSet(values, 0, getFeatureSet(), firstPosition,
303
            getCalculator().getCurrentPageSize(), null);
304
    }
305 23675 cordinyana
306 33385 cordinyana
    private void loadDataFromFeatureSet(final Feature[] values,
307
        final int valuesPosition, FeatureSet set, long initialIndex,
308
        final long howMany, final FeatureSelection selectedFeaturesToSkip)
309
        throws DataException {
310 24023 cordinyana
311 33385 cordinyana
        try {
312
            set.accept(new Visitor() {
313 33378 cordinyana
314 33385 cordinyana
                private int i = valuesPosition;
315 33378 cordinyana
316 33385 cordinyana
                public void visit(Object obj) throws VisitCanceledException,
317
                    BaseException {
318
                    if (i >= valuesPosition + howMany) {
319
                        throw new VisitCanceledException();
320
                    }
321
                    Feature current = (Feature) obj;
322
                    // Add the current Feature only if we don't skip selected
323
                    // features or the feature is not selected
324
                    if (selectedFeaturesToSkip == null
325
                        || !selectedFeaturesToSkip.isSelected(current)) {
326
                        values[i] = current.getCopy();
327
                        i++;
328
                    }
329
                }
330
            }, initialIndex);
331
        } catch (BaseException e) {
332
            if (e instanceof DataException) {
333
                throw ((DataException) e);
334
            } else {
335
                LOG.error("Error loading the data starting at position {}",
336
                    new Long(initialIndex), e);
337
            }
338
        }
339
    }
340 33378 cordinyana
341 33385 cordinyana
    private void loadFeatureSet() throws BaseException {
342
        if (featureSet != null) {
343
            featureSet.dispose();
344
        }
345
        featureSet = getFeatureStore().getFeatureSet(getFeatureQuery());
346 33657 cordinyana
        setDynObjectSet(featureSet.getDynObjectSet(), getMaxPageSize());
347 33385 cordinyana
    }
348 33378 cordinyana
349 33385 cordinyana
    public void delete(Feature feature) throws BaseException {
350
        if (featureSet == null) {
351
            // FIXME change to RuntimeDalException
352
            throw new IllegalStateException();
353
        }
354
        featureSet.delete(feature);
355
        reloadCurrentPage();
356
    }
357 33378 cordinyana
358 33385 cordinyana
    public void insert(EditableFeature feature) throws BaseException {
359
        if (featureSet == null) {
360
            // FIXME change to RuntimeDalException
361
            throw new IllegalStateException();
362
        }
363
        featureSet.insert(feature);
364
        reloadCurrentPage();
365
    }
366 23772 jjdelcerro
367 33385 cordinyana
    public void update(EditableFeature feature) throws BaseException {
368
        if (featureSet == null) {
369
            // FIXME change to RuntimeDalException
370
            throw new IllegalStateException();
371
        }
372
        featureSet.update(feature);
373
        reloadCurrentPage();
374
    }
375 33378 cordinyana
376 33385 cordinyana
    public FeatureType getFeatureType() {
377
        return featureSet.getDefaultFeatureType();
378
    }
379 33378 cordinyana
380 33385 cordinyana
    protected void doDispose() throws BaseException {
381
        initialSelection.dispose();
382
        featureSet.dispose();
383
    }
384 33378 cordinyana
385 33385 cordinyana
    public DynObject[] getCurrentPageDynObjects() {
386 33657 cordinyana
        Feature[] features = getCurrentPageFeatures();
387
        DynObject[] dynobjects = new DynObject[features.length];
388
        for (int i = 0; i < dynobjects.length; i++) {
389
            dynobjects[i] = new DynObjectFeatureFacade(features[i]);
390
        }
391
        return dynobjects;
392 33385 cordinyana
    }
393 31110 cordinyana
394 33385 cordinyana
    public DynObject getDynObjectAt(long index) throws BaseException {
395 33657 cordinyana
        return new DynObjectFeatureFacade(getFeatureAt(index));
396 33385 cordinyana
    }
397 31110 cordinyana
398 33385 cordinyana
}