Statistics
| Revision:

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

History | View | Annotate | Download (9.51 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;
28

    
29
import org.gvsig.fmap.dal.exception.DataException;
30
import org.gvsig.fmap.dal.feature.EditableFeature;
31
import org.gvsig.fmap.dal.feature.Feature;
32
import org.gvsig.fmap.dal.feature.FeatureQuery;
33
import org.gvsig.fmap.dal.feature.FeatureSet;
34
import org.gvsig.fmap.dal.feature.FeatureStore;
35
import org.gvsig.fmap.dal.feature.FeatureType;
36
import org.gvsig.tools.dispose.impl.AbstractDisposable;
37
import org.gvsig.tools.dynobject.DynObject;
38
import org.gvsig.tools.dynobject.DynObjectSet;
39
import org.gvsig.tools.exception.BaseException;
40
import org.gvsig.tools.visitor.VisitCanceledException;
41
import org.gvsig.tools.visitor.Visitor;
42
import org.slf4j.Logger;
43
import org.slf4j.LoggerFactory;
44

    
45
/**
46
 * Helper class to access the values of a FeatureCollection by position. Handles
47
 * pagination automatically to avoid filling the memory in case of big
48
 * collections.
49
 * 
50
 * TODO: evaluate if its more convenient to read values in the background when
51
 * the returned value is near the end of the page, instead of loading a page on
52
 * demand.
53
 * 
54
 * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
55
 */
56
public class FeaturePagingHelperImpl extends AbstractDisposable implements
57
                FeaturePagingHelper {
58

    
59
        private static final Logger LOG =
60
                        LoggerFactory.getLogger(FeaturePagingHelperImpl.class);
61

    
62
        private FeatureQuery query;
63

    
64
        private FeatureSet featureSet;
65

    
66
        private FeatureStore featureStore;
67

    
68
        private int maxPageSize;
69

    
70
        private long numPages;
71

    
72
        private long currentPage = -1;
73

    
74
        private Feature[] values;
75

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

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

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

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

    
140
                if (LOG.isDebugEnabled()) {
141
                        LOG.debug("FeaturePagingHelperImpl created with {} pages, "
142
                                        + "and a page size of {}", new Long(numPages), new Integer(
143
                                        pageSize));
144
                }
145
        }
146

    
147
        public int getMaxPageSize() {
148
                return maxPageSize;
149
        }
150

    
151
        public void setMaxPageSize(int pageSize) throws DataException {
152
                this.maxPageSize = pageSize;
153
                reloadCurrentPage();
154
        }
155

    
156
        public long getNumPages() {
157
                return numPages;
158
        }
159

    
160
        /**
161
         * Sets the number of pages.
162
         */
163
        private void setNumPages(long numPages) {
164
                this.numPages = numPages;
165
        }
166

    
167
        public long getCurrentPage() {
168
                return currentPage;
169
        }
170

    
171
        public void setCurrentPage(long page) throws DataException {
172

    
173
                if (LOG.isDebugEnabled()) {
174
                        LOG.debug("Current page: {}", Long.toString(page));
175
                }
176

    
177
                if (page < 0) {
178
                        throw new IndexOutOfBoundsException(
179
                                        "Error, unable to set helper current page to a "
180
                                                        + "negative value: " + page);
181
                }
182
                if (page >= getNumPages()) {
183
                        throw new IndexOutOfBoundsException(
184
                                        "Error, unable to set helper current page to the page num. "
185
                                                        + page + ", as the Collection only has "
186
                                                        + getNumPages() + " pages of Features");
187
                }
188
                currentPage = page;
189
                loadCurrentPageData();
190
        }
191

    
192
        public long getTotalSize() throws DataException {
193
                return getFeatureSet().getSize();
194
        }
195

    
196
        public Feature getFeatureAt(long index) throws DataException {
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 values[(int) positionForIndex];
208
        }
209

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

    
214
        public FeatureSet getFeatureSet() {
215
                return featureSet;
216
        }
217

    
218
        public void reloadCurrentPage() throws DataException {
219
                setNumPages(calculateNumPages());
220
                if (currentPage > -1) {
221
                        loadCurrentPageData();
222
                }
223
        }
224

    
225
        public void reload() throws DataException {
226
                loadFeatureSet();
227
                reloadCurrentPage();
228
        }
229

    
230
        public FeatureStore getFeatureStore() {
231
                return featureStore;
232
        }
233

    
234
        public FeatureQuery getFeatureQuery() {
235
                return query;
236
        }
237

    
238
        /**
239
         * Calculates the number of pages.
240
         */
241
        private long calculateNumPages() throws DataException {
242
                double num = getTotalSize();
243
                double pageSize = getMaxPageSize();
244

    
245
                return (long) Math.ceil(num / pageSize);
246
        }
247

    
248
        /**
249
         * Loads all the Features of the current page.
250
         */
251
        private void loadCurrentPageData() throws DataException {
252
                long t1 = 0;
253

    
254
                long currentPage = getCurrentPage();
255
                final int currentPageSize;
256
                if (currentPage < (numPages - 1)) {
257
                        currentPageSize = getMaxPageSize();
258
                } else {
259
                        currentPageSize =
260
                                        (int) (getTotalSize() - (currentPage * getMaxPageSize()));
261
                }
262

    
263
                values = new Feature[currentPageSize];
264

    
265
                long firstPosition = currentPage * getMaxPageSize();
266

    
267
                if (LOG.isDebugEnabled()) {
268
                        LOG.debug("Loading {} Features starting at position {}",
269
                                        new Integer(currentPageSize), new Long(firstPosition));
270
                }
271
                if (LOG.isTraceEnabled()) {
272
                        t1 = System.currentTimeMillis();
273
                }
274

    
275
                try {
276
                        getFeatureSet().accept(new Visitor() {
277
                                private int i = 0;
278
                                
279
                                public void visit(Object obj) throws VisitCanceledException,
280
                                                BaseException {
281
                                        if (i >= currentPageSize) {
282
                                                throw new VisitCanceledException();
283
                                        }
284
                                        values[i] = (Feature) obj;
285
                                        i++;
286
                                }
287
                        }, firstPosition);
288
                } catch (BaseException e) {
289
                        if (e instanceof DataException) {
290
                                throw ((DataException) e);
291
                        }
292
                        else {
293
                                LOG.error("Error loading the data starting at position {}",
294
                                                new Long(firstPosition), e);
295
                        }
296
                }
297

    
298
                if (LOG.isTraceEnabled()) {
299
                        long t2 = System.currentTimeMillis();
300
                        LOG.trace("Time to load {} features: {} ms", new Integer(
301
                                        currentPageSize), new Long(t2 - t1));
302
                }
303
        }
304

    
305
        private void loadFeatureSet() throws DataException {
306
                if (featureSet != null) {
307
                        featureSet.dispose();
308
                }
309
                featureSet = getFeatureStore().getFeatureSet(getFeatureQuery());
310
        }
311

    
312
        public void delete(Feature feature) throws DataException {
313
                if (featureSet == null) {
314
                        // FIXME change to RuntimeDalException
315
                        throw new IllegalStateException();
316
                }
317
                featureSet.delete(feature);
318
                reloadCurrentPage();
319
        }
320

    
321
        public void insert(EditableFeature feature) throws DataException {
322
                if (featureSet == null) {
323
                        // FIXME change to RuntimeDalException
324
                        throw new IllegalStateException();
325
                }
326
                featureSet.insert(feature);
327
                reloadCurrentPage();
328
        }
329

    
330
        public void update(EditableFeature feature) throws DataException {
331
                if (featureSet == null) {
332
                        // FIXME change to RuntimeDalException
333
                        throw new IllegalStateException();
334
                }
335
                featureSet.update(feature);
336
                reloadCurrentPage();
337
        }
338

    
339
        public FeatureType getFeatureType() {
340
                return featureSet.getDefaultFeatureType();
341
        }
342

    
343
        protected void doDispose() throws BaseException {
344
                featureSet.dispose();
345
        }
346

    
347
        public DynObject[] getCurrentPageDynObjects() {
348
                return getCurrentPageFeatures();
349
        }
350

    
351
        public DynObject getDynObjectAt(long index) throws BaseException {
352
                return getFeatureAt(index);
353
        }
354

    
355
        public DynObjectSet getDynObjectSet() {
356
                return getFeatureSet();
357
        }
358
}