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

History | View | Annotate | Download (22.1 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
package org.gvsig.fmap.dal.feature.paging.impl;
25

    
26
import java.util.Collection;
27
import java.util.Iterator;
28
import java.util.List;
29
import java.util.ListIterator;
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
    private boolean initialization_completed = false;
81
    /**
82
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
83
     * 
84
     * @param featureStore
85
     *            to extract data from
86
     * @throws DataException
87
     *             if there is an error initializing the helper
88
     */
89
    public FeaturePagingHelperImpl(FeatureStore featureStore)
90
        throws BaseException {
91
        this(featureStore, DEFAULT_PAGE_SIZE);
92
    }
93

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

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

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

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

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

    
168
    /**
169
     * @return the selectionUp status
170
     */
171
    protected boolean isSelectionUp() {
172
        return selectionUp;
173
    }
174

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

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

    
208
        if (pageForIndex != getCurrentPage()) {
209
            setCurrentPage(pageForIndex);
210
        }
211

    
212
        long positionForIndex = index - (getCurrentPage() * getMaxPageSize());
213

    
214
        if (positionForIndex >= features.length) {
215
            throw new FeatureIndexException(
216
                new IndexOutOfBoundsException("positionForIndex too big: "
217
                    + positionForIndex));
218
        } else {
219
            Feature feature = features[(int) positionForIndex];
220
            return feature;
221
        }
222
        
223
    }
224

    
225
    public Feature[] getCurrentPageFeatures() {
226
        return features;
227
    }
228

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

    
263
    public void reloadCurrentPage() throws BaseException {
264
        
265
        boolean sel_up = this.isSelectionUp();
266

    
267
        setSelectionUp(false);
268
        if (getCalculator().getCurrentPage() > -1) {
269
            loadCurrentPageData();
270
        }
271
        
272
        if (sel_up) {
273
            setSelectionUp(true);
274
        }
275
    }
276

    
277
    public void reload() throws BaseException {
278
        
279
        /*
280
         * Force re-creation of feature set
281
         */
282
        this.getFeatureSet(true);
283

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

    
300
    public FeatureStore getFeatureStore() {
301
        return featureStore;
302
    }
303

    
304
    public FeatureQuery getFeatureQuery() {
305
        return query;
306
    }
307

    
308
    /**
309
     * Loads all the Features of the current page.
310
     */
311
    protected void loadCurrentPageData() throws BaseException {
312
        if( !initialization_completed ) {
313
            return;
314
        }
315
        final int currentPageSize = getCalculator().getCurrentPageSize();
316
        final Feature[] values = new Feature[currentPageSize];
317

    
318
        long t1 = 0;
319
        if (LOG.isTraceEnabled()) {
320
            t1 = System.currentTimeMillis();
321
        }
322

    
323
        if (selectionUp) {
324
            loadCurrentPageDataWithSelectionUp(values);
325
        } else {
326
            loadCurrentPageDataNoSelection(values);
327
        }
328

    
329
        if (LOG.isTraceEnabled()) {
330
            long t2 = System.currentTimeMillis();
331
            LOG.trace("Time to load {} features: {} ms", new Integer(
332
                currentPageSize), new Long(t2 - t1));
333
        }
334

    
335
        this.features = values;
336
    }
337
    
338
    private void loadCurrentPageDataWithSelectionUp(final Feature[] values)
339
        throws BaseException {
340
        FeatureSelection selection = initialSelection;
341

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

    
384
    private void loadCurrentPageDataNoSelection(final Feature[] values)
385
        throws BaseException {
386

    
387
        long firstPosition = getCalculator().getInitialIndex();
388

    
389
        if (LOG.isDebugEnabled()) {
390
            LOG.debug("Loading {} Features starting at position {}",
391
                new Integer(getCalculator().getCurrentPageSize()), new Long(
392
                    firstPosition));
393
        }
394

    
395
        FeatureSet featureSet = getFeatureSet(false);
396
        try {
397
                loadDataFromFeatureSet(values, 0, featureSet, firstPosition,
398
                                getCalculator().getCurrentPageSize(), null);
399
        } catch(DataException ex) {
400
            throw ex;
401
            // } finally {
402
                // featureSet.dispose();
403
        }
404
        
405
    }
406

    
407
    private void loadDataFromFeatureSet(final Feature[] values,
408
        final int valuesPosition, FeatureSet set, long initialIndex,
409
        final long howMany, final FeatureSelection selectedFeaturesToSkip)
410
        throws DataException {
411

    
412
        try {
413
            set.accept(new Visitor() {
414

    
415
                private int i = valuesPosition;
416

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

    
442
    public void delete(Feature feature) throws BaseException {
443
        featureStore.delete(feature);
444
        /*
445
         * Force re-creation of feature set
446
         */
447
        this.getFeatureSet(true);
448

    
449
        reloadCurrentPage();
450
    }
451

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

    
459
        reloadCurrentPage();
460
    }
461

    
462
    public void update(EditableFeature feature) throws BaseException {
463
            featureStore.update(feature);
464
        /*
465
         * Force re-creation of feature set
466
         */
467
        this.getFeatureSet(true);
468

    
469
        reloadCurrentPage();
470
    }
471

    
472
    public FeatureType getFeatureType() {
473
        
474
        FeatureType ft = null;
475
        
476
        try {
477
            ft = featureStore.getDefaultFeatureType();
478
        } catch (DataException e) {
479
            LOG.error("Error while getting feature type: " +
480
                e.getMessage(), e);
481
        }
482
        return ft;
483
        
484
        /*
485
         * 
486
        FeatureSet featureSet = getFeatureSet();
487
        try {
488
            return featureSet.getDefaultFeatureType();
489
        } finally {
490
            featureSet.dispose();
491
        }
492
        */
493

    
494
        
495
    }
496

    
497
    protected void doDispose() throws BaseException {
498
        initialSelection.dispose();
499
        if (featSet != null) {
500
            try {
501
                featSet.dispose();
502
            } catch (Exception ex) {
503
                LOG.info("Error while disposing featset.", ex);
504
            }
505
        }
506
    }
507

    
508
    public DynObject[] getCurrentPageDynObjects() {
509
        Feature[] features = getCurrentPageFeatures();
510
        DynObject[] dynobjects = new DynObject[features.length];
511
        for (int i = 0; i < dynobjects.length; i++) {
512
            dynobjects[i] = new DynObjectFeatureFacade(features[i]);
513
        }
514
        return dynobjects;
515
    }
516

    
517
    public DynObject getDynObjectAt(long index) throws BaseException {
518
        return new DynObjectFeatureFacade(getFeatureAt(index));
519
    }
520

    
521
    public List asList() {
522
        return new FeaturePagingHelperList();
523
    }
524
    
525
    public List asListOfDynObjects() {
526
        return new DynObjectPagingHelperList();
527
    }    
528
    
529
    private class FeaturePagingHelperList extends PagingHelperList {
530
        public Object get(int i) {
531
            try {
532
                return getFeatureAt(i);
533
            } catch (BaseException ex) {
534
                throw  new RuntimeException(ex);
535
            }
536
        }
537
    }
538
    
539
    private class DynObjectPagingHelperList extends PagingHelperList {
540
        public Object get(int i) {
541
            try {
542
                return getDynObjectAt(i);
543
            } catch (BaseException ex) {
544
                throw  new RuntimeException(ex);
545
            }
546
        }
547
    }
548
    
549
    private abstract class PagingHelperList implements List {
550

    
551
        public int size() {
552
            try {
553
                return (int) getFeatureSet(false).getSize();
554
            } catch (DataException ex) {
555
                throw  new RuntimeException(ex);
556
            }
557
        }
558

    
559
        public boolean isEmpty() {
560
            try {
561
                return getFeatureSet(false).isEmpty();
562
            } catch (DataException ex) {
563
                throw  new RuntimeException(ex);
564
            }
565
        }
566

    
567
        public Iterator iterator() {
568
            try {
569
                return getFeatureSet(false).fastIterator();
570
            } catch (DataException ex) {
571
                throw  new RuntimeException(ex);
572
            }
573
        }
574

    
575
        public boolean contains(Object o) {
576
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
577
        }
578

    
579
        public Object[] toArray() {
580
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
581
        }
582

    
583
        public Object[] toArray(Object[] ts) {
584
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
585
        }
586

    
587
        public boolean add(Object e) {
588
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
589
        }
590

    
591
        public boolean remove(Object o) {
592
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
593
        }
594

    
595
        public boolean containsAll(Collection clctn) {
596
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
597
        }
598

    
599
        public boolean addAll(Collection clctn) {
600
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
601
        }
602

    
603
        public boolean addAll(int i, Collection clctn) {
604
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
605
        }
606

    
607
        public boolean removeAll(Collection clctn) {
608
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
609
        }
610

    
611
        public boolean retainAll(Collection clctn) {
612
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
613
        }
614

    
615
        public void clear() {
616
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
617
        }
618

    
619
        public Object set(int i, Object e) {
620
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
621
        }
622

    
623
        public void add(int i, Object e) {
624
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
625
        }
626

    
627
        public Object remove(int i) {
628
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
629
        }
630

    
631
        public int indexOf(Object o) {
632
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
633
        }
634

    
635
        public int lastIndexOf(Object o) {
636
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
637
        }
638

    
639
        public ListIterator listIterator() {
640
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
641
        }
642

    
643
        public ListIterator listIterator(int i) {
644
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
645
        }
646

    
647
        public List subList(int i, int i1) {
648
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
649
        }
650
        
651
    }
652
}