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

History | View | Annotate | Download (37 KB)

1 40559 jjdelcerro
/**
2
 * gvSIG. Desktop Geographic Information System.
3 40435 jjdelcerro
 *
4 44977 jjdelcerro
 * Copyright (C) 2007-2020 gvSIG Association.
5 40435 jjdelcerro
 *
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 40559 jjdelcerro
 * as published by the Free Software Foundation; either version 3
9 40435 jjdelcerro
 * 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 40559 jjdelcerro
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23 40435 jjdelcerro
 */
24
package org.gvsig.fmap.dal.feature.paging.impl;
25
26 43660 jjdelcerro
import java.util.ArrayList;
27 41212 jjdelcerro
import java.util.Collection;
28 43660 jjdelcerro
import java.util.Date;
29 41212 jjdelcerro
import java.util.Iterator;
30
import java.util.List;
31
import java.util.ListIterator;
32 45425 jjdelcerro
import java.util.logging.Level;
33 47198 jjdelcerro
import org.apache.commons.lang3.builder.ToStringBuilder;
34 44840 jjdelcerro
import org.apache.commons.lang3.mutable.MutableBoolean;
35 40435 jjdelcerro
import org.slf4j.Logger;
36
import org.slf4j.LoggerFactory;
37
38
import org.gvsig.fmap.dal.exception.DataException;
39
import org.gvsig.fmap.dal.feature.EditableFeature;
40
import org.gvsig.fmap.dal.feature.Feature;
41
import org.gvsig.fmap.dal.feature.FeatureQuery;
42
import org.gvsig.fmap.dal.feature.FeatureSelection;
43
import org.gvsig.fmap.dal.feature.FeatureSet;
44
import org.gvsig.fmap.dal.feature.FeatureStore;
45
import org.gvsig.fmap.dal.feature.FeatureType;
46 41819 fdiaz
import org.gvsig.fmap.dal.feature.exception.ConcurrentDataModificationException;
47 40435 jjdelcerro
import org.gvsig.fmap.dal.feature.exception.FeatureIndexException;
48 42775 jjdelcerro
import org.gvsig.fmap.dal.feature.impl.dynobjectutils.DynObjectFeatureFacade;
49
import org.gvsig.fmap.dal.feature.paging.FacadeOfAFeaturePagingHelper;
50 40435 jjdelcerro
import org.gvsig.fmap.dal.feature.paging.FeaturePagingHelper;
51 45196 jjdelcerro
import org.gvsig.tools.dispose.Disposable;
52 45425 jjdelcerro
import org.gvsig.tools.dispose.DisposeUtils;
53 40435 jjdelcerro
import org.gvsig.tools.dynobject.DynObject;
54
import org.gvsig.tools.dynobject.DynObjectSet;
55
import org.gvsig.tools.dynobject.impl.DefaultDynObjectPagingHelper;
56
import org.gvsig.tools.exception.BaseException;
57 44253 jjdelcerro
import org.gvsig.tools.util.UnmodifiableBasicList;
58
import org.gvsig.tools.util.UnmodifiableBasicList64;
59 40435 jjdelcerro
import org.gvsig.tools.visitor.VisitCanceledException;
60
import org.gvsig.tools.visitor.Visitor;
61
62
/**
63
 * Helper class to access the values of a FeatureCollection by position. Handles
64
 * pagination automatically to avoid filling the memory in case of big
65
 * collections.
66 41819 fdiaz
 *
67 40435 jjdelcerro
 * TODO: evaluate if its more convenient to read values in the background when
68
 * the returned value is near the end of the page, instead of loading a page on
69
 * demand.
70 41819 fdiaz
 *
71 40435 jjdelcerro
 * @author gvSIG Team
72
 */
73 44977 jjdelcerro
@SuppressWarnings("UseSpecificCatch")
74 40435 jjdelcerro
public class FeaturePagingHelperImpl extends DefaultDynObjectPagingHelper
75 44977 jjdelcerro
        implements FeaturePagingHelper {
76 40435 jjdelcerro
77 43660 jjdelcerro
    private static final Logger LOG = LoggerFactory.getLogger(FeaturePagingHelperImpl.class);
78 40435 jjdelcerro
79 43660 jjdelcerro
    private static class Page {
80
81 43691 jjdelcerro
        private Feature[] features;
82 43660 jjdelcerro
        private final long number;
83
        private final int size;
84
        private long lastaccess;
85 44977 jjdelcerro
86 43660 jjdelcerro
        public Page(long number, int size) {
87
            this.size = size;
88
            this.number = number;
89
            this.features = new Feature[size];
90
            this.lastaccess = 0;
91
        }
92
93
        public void setFeature(int i, Feature copy) {
94
            this.features[i] = copy;
95
        }
96 44977 jjdelcerro
97 43660 jjdelcerro
        public Feature[] getFeatures() {
98
            this.lastaccess = (new Date()).getTime();
99
            return this.features;
100
        }
101 44977 jjdelcerro
102 43660 jjdelcerro
        public long getPageNumber() {
103
            return this.number;
104
        }
105 44977 jjdelcerro
106 43660 jjdelcerro
        public long getLastAccess() {
107
            return this.lastaccess;
108
        }
109 44977 jjdelcerro
110 43660 jjdelcerro
        public int size() {
111
            return this.size;
112
        }
113 44977 jjdelcerro
114 43691 jjdelcerro
        public void dispose() {
115
            for (int i = 0; i < features.length; i++) {
116
                features[i] = null;
117
            }
118
            this.features = null;
119
            this.lastaccess = 0;
120
        }
121 44977 jjdelcerro
    }
122
123 43660 jjdelcerro
    private static class PageCache {
124
125
        private final int maxpages;
126 43691 jjdelcerro
        private List<Page> pages;
127 44977 jjdelcerro
128 43660 jjdelcerro
        public PageCache(int maxpages) {
129
            this.maxpages = maxpages;
130
            this.pages = new ArrayList<>();
131
        }
132 44977 jjdelcerro
133 43691 jjdelcerro
        public void clear() {
134 44977 jjdelcerro
            pages.forEach((page) -> {
135 43691 jjdelcerro
                page.dispose();
136 44977 jjdelcerro
            });
137
            this.pages = new ArrayList<>();
138 43691 jjdelcerro
        }
139 44977 jjdelcerro
140 43660 jjdelcerro
        public Page get(long pageNumber) {
141 44977 jjdelcerro
            for (Page page : pages) {
142
                if (page.getPageNumber() == pageNumber) {
143 43660 jjdelcerro
                    return page;
144
                }
145
            }
146
            return null;
147
        }
148 44977 jjdelcerro
149 43660 jjdelcerro
        public void add(Page page) {
150 44977 jjdelcerro
            if (this.pages.size() < this.maxpages) {
151 43660 jjdelcerro
                this.pages.add(page);
152
                return;
153
            }
154
            int toDrop = 0;
155 44977 jjdelcerro
            for (int i = 0; i < this.pages.size(); i++) {
156
                if (this.pages.get(i).getLastAccess() < this.pages.get(toDrop).getLastAccess()) {
157 43660 jjdelcerro
                    toDrop = i;
158
                }
159
            }
160
            this.pages.set(toDrop, page);
161
        }
162
    }
163 44977 jjdelcerro
164 40435 jjdelcerro
    private FeatureQuery query;
165
166
    private FeatureStore featureStore;
167
168 44977 jjdelcerro
    /**
169
     * If the selected Features must be returned as the first ones. *
170
     */
171 40435 jjdelcerro
    private boolean selectionUp = false;
172
173
    private FeatureSet featSet = null;
174
175
    private Feature[] features = null;
176 43660 jjdelcerro
    private PageCache cachedPages = null;
177 40435 jjdelcerro
178 41212 jjdelcerro
    private boolean initialization_completed = false;
179 42807 jjdelcerro
180
    private FeatureSelection selection = null;
181 44977 jjdelcerro
182 40435 jjdelcerro
    /**
183
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
184 41819 fdiaz
     *
185 44977 jjdelcerro
     * @param featureStore to extract data from
186
     * @throws DataException if there is an error initializing the helper
187 40435 jjdelcerro
     */
188
    public FeaturePagingHelperImpl(FeatureStore featureStore)
189 44977 jjdelcerro
            throws BaseException {
190 40435 jjdelcerro
        this(featureStore, DEFAULT_PAGE_SIZE);
191
    }
192
193
    /**
194
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
195 41819 fdiaz
     *
196 44977 jjdelcerro
     * @param featureStore to extract data from
197
     * @param pageSize the number of elements per page data
198
     * @throws DataException if there is an error initializing the helper
199 40435 jjdelcerro
     */
200
    public FeaturePagingHelperImpl(FeatureStore featureStore, int pageSize)
201 44977 jjdelcerro
            throws BaseException {
202 40435 jjdelcerro
        this(featureStore, null, pageSize);
203
    }
204
205
    /**
206
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
207 41819 fdiaz
     *
208 44977 jjdelcerro
     * @param featureStore to extract data from
209
     * @param featureQuery
210
     * @throws DataException if there is an error initializing the helper
211 40435 jjdelcerro
     */
212
    public FeaturePagingHelperImpl(FeatureStore featureStore,
213 44977 jjdelcerro
            FeatureQuery featureQuery) throws BaseException {
214 40435 jjdelcerro
        this(featureStore, featureQuery, DEFAULT_PAGE_SIZE);
215
    }
216
217
    /**
218
     * Constructs a FeaturePagingHelperImpl from data of a FeatureStore.
219 41819 fdiaz
     *
220 44977 jjdelcerro
     * @param featureStore
221
     * @param featureQuery
222
     * @param pageSize the number of elements per page data
223
     * @throws DataException if there is an error initializing the helper
224 40435 jjdelcerro
     */
225
    public FeaturePagingHelperImpl(FeatureStore featureStore,
226 44977 jjdelcerro
            FeatureQuery featureQuery, int pageSize) throws BaseException {
227 40435 jjdelcerro
        super();
228 43660 jjdelcerro
        this.cachedPages = new PageCache(3);
229 44977 jjdelcerro
        FeatureQuery theQuery = featureQuery;
230 40435 jjdelcerro
        if (featureQuery == null) {
231 44977 jjdelcerro
            theQuery = featureStore.createFeatureQuery();
232
            theQuery.setFeatureType(featureStore.getDefaultFeatureType());
233 40435 jjdelcerro
        }
234
235
        this.featureStore = featureStore;
236 45425 jjdelcerro
        DisposeUtils.bind(this.featureStore);
237
238 44977 jjdelcerro
        this.query = theQuery;
239 40435 jjdelcerro
        this.query.setPageSize(pageSize);
240
241 44977 jjdelcerro
        setDefaultCalculator(() -> {
242
            FeatureSet featureSet = getFeatureSet(false);
243
            try {
244
                return featureSet.getSize();
245
            } catch (BaseException e) {
246
                LOG.warn("Error getting the size of the FeatureSet: " + featureSet, e);
247
                return 0l;
248 40435 jjdelcerro
            }
249
        }, pageSize);
250 40595 jldominguez
        if (LOG.isDebugEnabled()) {
251 44977 jjdelcerro
            LOG.debug("FeaturePagingHelperImpl created with {} pages, and a page size of {}",
252
                    getCalculator().getNumPages(), pageSize
253
            );
254 40595 jldominguez
        }
255 41212 jjdelcerro
        this.initialization_completed = true;
256 40435 jjdelcerro
    }
257
258
    /**
259
     * @return the selectionUp status
260
     */
261 44977 jjdelcerro
    @Override
262 41630 jjdelcerro
    public boolean isSelectionUp() {
263 40435 jjdelcerro
        return selectionUp;
264
    }
265 44977 jjdelcerro
266
    @Override
267 42807 jjdelcerro
    public FeatureSelection getSelection() {
268
        if (selection == null) {
269
            try {
270
                return getFeatureStore().getFeatureSelection();
271
            } catch (Exception e) {
272
                LOG.warn("Error getting the selection", e);
273
            }
274
        }
275
        return selection;
276
    }
277 44977 jjdelcerro
278
    @Override
279 42807 jjdelcerro
    public void setSelection(FeatureSelection selection) {
280 46132 fdiaz
        DisposeUtils.disposeQuietly(this.selection);
281 42807 jjdelcerro
        this.selection = selection;
282 46132 fdiaz
        DisposeUtils.bind(this.selection);
283 42807 jjdelcerro
    }
284 44977 jjdelcerro
285 42807 jjdelcerro
    @Override
286 40435 jjdelcerro
    public void setSelectionUp(boolean selectionUp) {
287
        this.selectionUp = selectionUp;
288
        try {
289 43728 jjdelcerro
            this.cachedPages.clear();
290 42807 jjdelcerro
            FeatureSelection currentSelection = getSelection();
291 41630 jjdelcerro
            if (selectionUp && !currentSelection.isEmpty()) {
292 44977 jjdelcerro
//                initialSelection =(FeatureSelection) currentSelection.clone();
293 40435 jjdelcerro
                setCalculator(new OneSubsetOneSetPagingCalculator(
294 44977 jjdelcerro
                        new FeatureSetSizeableDelegate(currentSelection),
295
                        new FeatureSetSizeableDelegate(getFeatureSet(false)),
296
                        getMaxPageSize()));
297 40435 jjdelcerro
            } else {
298
                setDefaultCalculator(new FeatureSetSizeableDelegate(
299 44977 jjdelcerro
                        getFeatureSet(false)), getMaxPageSize()
300
                );
301 40435 jjdelcerro
            }
302
        } catch (BaseException e) {
303 44977 jjdelcerro
            LOG.warn("Error setting the selection up setting to: " + selectionUp, e);
304 40435 jjdelcerro
        }
305
    }
306
307 44977 jjdelcerro
    @Override
308 42991 jbadia
    public synchronized Feature getFeatureAt(long index) throws BaseException {
309 40435 jjdelcerro
        // Check if we have currently loaded the viewed page data,
310
        // or we need to load a new one
311 44977 jjdelcerro
        int maxPageSize = getMaxPageSize();
312
        long currentPage = getCurrentPage();
313
        long currentPage2 = currentPage;
314
315 42991 jbadia
        long pageForIndex = (long) Math.floor(index / maxPageSize);
316 40435 jjdelcerro
317 42991 jbadia
        if (pageForIndex != currentPage) {
318 40435 jjdelcerro
            setCurrentPage(pageForIndex);
319 42991 jbadia
            currentPage2 = getCurrentPage();
320 40435 jjdelcerro
        }
321
322 42991 jbadia
        long positionForIndex = index - (currentPage2 * maxPageSize);
323 40435 jjdelcerro
324 41268 jjdelcerro
        if (positionForIndex >= getCurrentPageFeatures().length) {
325 40435 jjdelcerro
            throw new FeatureIndexException(
326 44977 jjdelcerro
                    new IndexOutOfBoundsException("positionForIndex too big: "
327
                            + positionForIndex));
328 40435 jjdelcerro
        } else {
329 41268 jjdelcerro
            Feature feature = getCurrentPageFeatures()[(int) positionForIndex];
330 41212 jjdelcerro
            return feature;
331 40435 jjdelcerro
        }
332 41819 fdiaz
333 40435 jjdelcerro
    }
334
335 44977 jjdelcerro
    @Override
336 40435 jjdelcerro
    public Feature[] getCurrentPageFeatures() {
337 44977 jjdelcerro
        if (this.features == null) {
338 41268 jjdelcerro
            try {
339
                this.loadCurrentPageData();
340
            } catch (BaseException ex) {
341
                // Do nothing
342
            }
343 44977 jjdelcerro
            if (this.features == null) {
344 41268 jjdelcerro
                String msg = "Can't retrieve the features from current page.";
345
                LOG.warn(msg);
346
                throw new RuntimeException(msg);
347
            }
348
        }
349 40435 jjdelcerro
        return features;
350
    }
351 44977 jjdelcerro
352 44794 omartinez
    @Override
353
    public FeatureSet getFeatureSet() {
354
        return this.getFeatureSet(false);
355
    }
356 40435 jjdelcerro
357
    /**
358 44977 jjdelcerro
     * Gets the feature set. The boolean tells whether we must create the
359
     * featureset again (for example perhaps we need it after a feature has been
360
     * added/removed)
361 40435 jjdelcerro
     */
362
    private FeatureSet getFeatureSet(boolean reset) {
363 41819 fdiaz
364 40435 jjdelcerro
        if (featSet == null || reset) {
365 41819 fdiaz
366 40435 jjdelcerro
            if (featSet != null) {
367
                try {
368
                    featSet.dispose();
369 45738 fdiaz
                    featSet = null;
370 40435 jjdelcerro
                } catch (Exception ex) {
371
                    LOG.info("Error while disposing featset.", ex);
372
                }
373
            }
374 41819 fdiaz
375 40435 jjdelcerro
            try {
376 41819 fdiaz
                FeatureStore featureStore = getFeatureStore();
377 40435 jjdelcerro
                synchronized (featureStore) {
378 41819 fdiaz
                    featSet = featureStore.getFeatureSet(getFeatureQuery());
379 40435 jjdelcerro
                }
380
            } catch (DataException e) {
381 47227 fdiaz
                throw new RuntimeException("Error getting a feature set with the query " + getFeatureQuery(), e);
382 40435 jjdelcerro
            }
383
        }
384
        return featSet;
385
    }
386 41819 fdiaz
387 43691 jjdelcerro
    @Override
388 40435 jjdelcerro
    public DynObjectSet getDynObjectSet() {
389 44977 jjdelcerro
        return getFeatureSet(false).getDynObjectSet();
390 40435 jjdelcerro
    }
391
392 43691 jjdelcerro
    @Override
393 40435 jjdelcerro
    public void reloadCurrentPage() throws BaseException {
394
        boolean sel_up = this.isSelectionUp();
395 44977 jjdelcerro
        try {
396
            setSelectionUp(false);
397
            if (getCalculator().getCurrentPage() > -1) {
398
                this.cachedPages.clear();
399
                loadCurrentPageData();
400
            }
401
        } finally {
402
            if (sel_up) {
403
                setSelectionUp(true);
404
            }
405 40435 jjdelcerro
        }
406
    }
407
408 43691 jjdelcerro
    @Override
409 40435 jjdelcerro
    public void reload() throws BaseException {
410 41819 fdiaz
411 43726 jjdelcerro
        this.cachedPages.clear();
412 40435 jjdelcerro
        /*
413
         * Force re-creation of feature set
414
         */
415
        this.getFeatureSet(true);
416
417 44977 jjdelcerro
        setDefaultCalculator(() -> {
418
            FeatureSet featureSet = getFeatureSet(false);
419
            try {
420
                return featureSet.getSize();
421
            } catch (BaseException e) {
422
                LOG.warn("Error getting the size of the FeatureSet: "+ featureSet, e);
423
                return 0l;
424 40435 jjdelcerro
            }
425
        }, getCalculator().getMaxPageSize());
426 45154 jjdelcerro
//        reloadCurrentPage();
427 40435 jjdelcerro
    }
428
429 44977 jjdelcerro
    @Override
430 40435 jjdelcerro
    public FeatureStore getFeatureStore() {
431
        return featureStore;
432
    }
433
434 44977 jjdelcerro
    @Override
435 40435 jjdelcerro
    public FeatureQuery getFeatureQuery() {
436
        return query;
437
    }
438
439
    /**
440
     * Loads all the Features of the current page.
441 44977 jjdelcerro
     *
442 43660 jjdelcerro
     * @throws org.gvsig.tools.exception.BaseException
443 40435 jjdelcerro
     */
444 43660 jjdelcerro
    @Override
445 42991 jbadia
    protected synchronized void loadCurrentPageData() throws BaseException {
446 44977 jjdelcerro
        if (!initialization_completed) {
447 41212 jjdelcerro
            return;
448
        }
449 40435 jjdelcerro
        final int currentPageSize = getCalculator().getCurrentPageSize();
450 43660 jjdelcerro
        final long currentPage = getCalculator().getCurrentPage();
451
        Page page = this.cachedPages.get(currentPage);
452 44977 jjdelcerro
        if (page == null) {
453 43660 jjdelcerro
            page = new Page(currentPage, currentPageSize);
454 40435 jjdelcerro
455 43660 jjdelcerro
            long t1 = 0;
456
            if (LOG.isTraceEnabled()) {
457
                t1 = System.currentTimeMillis();
458
            }
459 40435 jjdelcerro
460 43660 jjdelcerro
            if (selectionUp) {
461
                loadCurrentPageDataWithSelectionUp(page);
462
            } else {
463
                loadCurrentPageDataNoSelection(page);
464
            }
465 40435 jjdelcerro
466 43660 jjdelcerro
            if (LOG.isTraceEnabled()) {
467
                long t2 = System.currentTimeMillis();
468
                LOG.trace("Time to load {} features: {} ms", currentPageSize, t2 - t1);
469
            }
470
            this.cachedPages.add(page);
471 40435 jjdelcerro
        }
472 43660 jjdelcerro
        this.features = page.getFeatures();
473 40435 jjdelcerro
    }
474 41819 fdiaz
475 43660 jjdelcerro
    private void loadCurrentPageDataWithSelectionUp(final Page page)
476 41630 jjdelcerro
            throws BaseException {
477 44977 jjdelcerro
        FeatureSelection theSelection = getSelection();
478
        if (theSelection == null) {
479 43660 jjdelcerro
            loadCurrentPageDataNoSelection(page);
480 41630 jjdelcerro
        } else {
481
            FeatureSet set = getFeatureSet(false);
482
            try {
483
                OneSubsetOneSetPagingCalculator twoSetsCalculator = null;
484
                if (getCalculator() instanceof OneSubsetOneSetPagingCalculator) {
485 44977 jjdelcerro
                    twoSetsCalculator = (OneSubsetOneSetPagingCalculator) getCalculator();
486 41630 jjdelcerro
                } else {
487 44977 jjdelcerro
                    twoSetsCalculator = new OneSubsetOneSetPagingCalculator(
488
                                    new FeatureSetSizeableDelegate(theSelection),
489 41630 jjdelcerro
                                    new FeatureSetSizeableDelegate(set),
490 44977 jjdelcerro
                                    getMaxPageSize(), getCalculator().getCurrentPage()
491
                    );
492 41630 jjdelcerro
                    setCalculator(twoSetsCalculator);
493
                }
494 44977 jjdelcerro
                // First load values from the selection, if the current page has
495 41630 jjdelcerro
                // elements from it
496
                if (twoSetsCalculator.hasCurrentPageAnyValuesInFirstSet()) {
497 44977 jjdelcerro
                    loadDataFromFeatureSet(page, 0, theSelection,
498 41630 jjdelcerro
                            twoSetsCalculator.getFirstSetInitialIndex(),
499 44977 jjdelcerro
                            twoSetsCalculator.getFirstSetHowMany(), null
500
                    );
501 41630 jjdelcerro
                }
502 44977 jjdelcerro
                // Next, load values from the FeatureSet if the current page has values
503 41630 jjdelcerro
                // from it
504
                if (twoSetsCalculator.hasCurrentPageAnyValuesInSecondSet()) {
505
                    loadDataFromFeatureSet(
506 43660 jjdelcerro
                            page,
507 41630 jjdelcerro
                            // The cast will work as that size will be <= maxpagesize,
508
                            // which is an int
509
                            (int) twoSetsCalculator.getFirstSetHowMany(), set,
510
                            twoSetsCalculator.getSecondSetInitialIndex(),
511 44977 jjdelcerro
                            twoSetsCalculator.getSecondSetHowMany(), theSelection
512
                    );
513 41630 jjdelcerro
                }
514
            } finally {
515 44977 jjdelcerro
                // This is the feature set we dont want to lose it
516 41630 jjdelcerro
                // set.dispose();
517
            }
518 40435 jjdelcerro
        }
519
    }
520
521 43660 jjdelcerro
    private void loadCurrentPageDataNoSelection(final Page page)
522 44977 jjdelcerro
            throws BaseException {
523 40435 jjdelcerro
524
        long firstPosition = getCalculator().getInitialIndex();
525
526
        if (LOG.isDebugEnabled()) {
527 44977 jjdelcerro
            LOG.debug("Loading {} Features starting at position {}",
528
                    getCalculator().getCurrentPageSize(), firstPosition
529 43660 jjdelcerro
            );
530 40435 jjdelcerro
        }
531
532
        FeatureSet featureSet = getFeatureSet(false);
533
        try {
534 44977 jjdelcerro
            loadDataFromFeatureSet(page, 0, featureSet, firstPosition,
535
                    getCalculator().getCurrentPageSize(), null);
536 45738 fdiaz
        } catch (Exception ex) {
537 40435 jjdelcerro
            throw ex;
538 44977 jjdelcerro
        } finally {
539
            // This is the feature set we dont want to lose it
540
            // featureSet.dispose();
541 40435 jjdelcerro
        }
542
    }
543
544 43660 jjdelcerro
    private void loadDataFromFeatureSet(final Page page,
545 44977 jjdelcerro
            final int valuesPosition, FeatureSet set, long initialIndex,
546
            final long howMany, final FeatureSelection selectedFeaturesToSkip)
547
            throws DataException {
548 40435 jjdelcerro
549
        try {
550 44840 jjdelcerro
            final MutableBoolean errorReported = new MutableBoolean(false);
551 40435 jjdelcerro
            set.accept(new Visitor() {
552
                private int i = valuesPosition;
553
554 43660 jjdelcerro
                @Override
555 40435 jjdelcerro
                public void visit(Object obj) throws VisitCanceledException,
556 44977 jjdelcerro
                        BaseException {
557 40435 jjdelcerro
                    if (i >= valuesPosition + howMany) {
558
                        throw new VisitCanceledException();
559
                    }
560
                    Feature current = (Feature) obj;
561
                    // Add the current Feature only if we don't skip selected
562
                    // features or the feature is not selected
563
                    if (selectedFeaturesToSkip == null
564 44977 jjdelcerro
                            || !selectedFeaturesToSkip.isSelected(current)) {
565 41630 jjdelcerro
                        try {
566 44977 jjdelcerro
                            page.setFeature(i, current.getCopy());
567 41630 jjdelcerro
                            i++;
568 44977 jjdelcerro
                        } catch (Exception ex) {
569 41630 jjdelcerro
                            // Aqui no deberia petar, pero...
570
                            // me he encontrado un caso que tenia una referencia a
571 41819 fdiaz
                            // una feature seleccionada que ya no existia. No se como
572 41630 jjdelcerro
                            // habia pasado, se habia quedado de antes guardada en el
573
                            // proyecto pero la feature ya no existia, y eso hacia que
574
                            // petase al intentar leer de disco la feature a partir
575
                            // de una referencia no valida.
576 44977 jjdelcerro
                            if (!errorReported.booleanValue()) {
577
                                // Solo sacamos un error por pagina de datos.
578
                                LOG.warn("Problemas recuperando feature.", ex);
579
                                errorReported.setTrue();
580 44840 jjdelcerro
                            }
581 41630 jjdelcerro
                        }
582 40435 jjdelcerro
                    }
583
                }
584 43358 jjdelcerro
            }, initialIndex, howMany);
585 44977 jjdelcerro
        } catch (VisitCanceledException ex) {
586 43358 jjdelcerro
            // Do nothing
587 46517 fdiaz
        } catch (RuntimeException e) {
588
            throw e;
589 45738 fdiaz
        } catch (Exception e) {
590 40435 jjdelcerro
            if (e instanceof DataException) {
591
                throw ((DataException) e);
592
            } else {
593 44977 jjdelcerro
                LOG.warn("Error loading the data starting at position {}", initialIndex, e);
594 40435 jjdelcerro
            }
595
        }
596
    }
597
598 44977 jjdelcerro
    @Override
599 40435 jjdelcerro
    public void delete(Feature feature) throws BaseException {
600
        featureStore.delete(feature);
601
        /*
602
         * Force re-creation of feature set
603
         */
604
        this.getFeatureSet(true);
605
606
        reloadCurrentPage();
607
    }
608
609 44977 jjdelcerro
    @Override
610 40435 jjdelcerro
    public void insert(EditableFeature feature) throws BaseException {
611 44977 jjdelcerro
        featureStore.insert(feature);
612 40435 jjdelcerro
        /*
613
         * Force re-creation of feature set
614
         */
615
        this.getFeatureSet(true);
616
617
        reloadCurrentPage();
618
    }
619 44977 jjdelcerro
620
    @Override
621 44488 jjdelcerro
    public boolean isEmpty() {
622
        try {
623
            return getFeatureSet(false).isEmpty();
624
        } catch (ConcurrentDataModificationException ex) {
625 46483 fdiaz
            LOG.warn("ConcurrentDataModification error asking about the emptiness of the list. Retrying reloading data. "+(featSet==null?0:featSet.hashCode()));
626 44488 jjdelcerro
            try {
627
                reload();
628
            } catch (BaseException e) {
629 46483 fdiaz
                LOG.warn("Error reloading data. "+(featSet==null?0:featSet.hashCode()), e);
630 44488 jjdelcerro
                throw new RuntimeException(e);
631
            }
632
            try {
633
                return getFeatureSet(false).isEmpty();
634 45425 jjdelcerro
            } catch (RuntimeException e) {
635
                throw  e;
636
            } catch (Exception e) {
637 46483 fdiaz
                LOG.warn("Error asking about the emptiness of the list after reloading data. "+(featSet==null?0:featSet.hashCode()), e);
638 44488 jjdelcerro
                throw new RuntimeException(e);
639
            }
640 45425 jjdelcerro
        } catch (Exception ex) {
641 44977 jjdelcerro
            throw new RuntimeException(ex);
642 44488 jjdelcerro
        }
643
    }
644 40435 jjdelcerro
645 44977 jjdelcerro
    @Override
646 40435 jjdelcerro
    public void update(EditableFeature feature) throws BaseException {
647 44977 jjdelcerro
        featureStore.update(feature);
648 40435 jjdelcerro
        /*
649
         * Force re-creation of feature set
650
         */
651
        this.getFeatureSet(true);
652
653
        reloadCurrentPage();
654
    }
655
656 44977 jjdelcerro
    @Override
657 40435 jjdelcerro
    public FeatureType getFeatureType() {
658 41819 fdiaz
659 40435 jjdelcerro
        FeatureType ft = null;
660 41819 fdiaz
661 40435 jjdelcerro
        try {
662
            ft = featureStore.getDefaultFeatureType();
663
        } catch (DataException e) {
664 44977 jjdelcerro
            LOG.warn("Error while getting feature type: "+ e.getMessage(), e);
665 40435 jjdelcerro
        }
666
        return ft;
667
    }
668
669 44977 jjdelcerro
    @Override
670 40435 jjdelcerro
    protected void doDispose() throws BaseException {
671 46132 fdiaz
        DisposeUtils.disposeQuietly(this.featSet);
672
        DisposeUtils.disposeQuietly(this.featureStore);
673
        DisposeUtils.disposeQuietly(this.selection);
674 40435 jjdelcerro
    }
675
676 44977 jjdelcerro
    @Override
677 40435 jjdelcerro
    public DynObject[] getCurrentPageDynObjects() {
678 44977 jjdelcerro
        Feature[] theFeatures = getCurrentPageFeatures();
679
        DynObject[] dynobjects = new DynObject[theFeatures.length];
680 40435 jjdelcerro
        for (int i = 0; i < dynobjects.length; i++) {
681 44977 jjdelcerro
            dynobjects[i] = new DynObjectFeatureFacade(theFeatures[i]);
682 40435 jjdelcerro
        }
683
        return dynobjects;
684
    }
685
686 44253 jjdelcerro
    @Override
687 40435 jjdelcerro
    public DynObject getDynObjectAt(long index) throws BaseException {
688
        return new DynObjectFeatureFacade(getFeatureAt(index));
689
    }
690
691 44253 jjdelcerro
    @Override
692 41212 jjdelcerro
    public List asList() {
693
        return new FeaturePagingHelperList();
694
    }
695 41819 fdiaz
696 44253 jjdelcerro
    @Override
697 41212 jjdelcerro
    public List asListOfDynObjects() {
698
        return new DynObjectPagingHelperList();
699 41819 fdiaz
    }
700
701 41212 jjdelcerro
    private class FeaturePagingHelperList extends PagingHelperList {
702 44977 jjdelcerro
703 44253 jjdelcerro
        @Override
704 41212 jjdelcerro
        public Object get(int i) {
705 44253 jjdelcerro
            return this.get64(i);
706
        }
707
708
        @Override
709
        public Object get64(long i) {
710 41212 jjdelcerro
            try {
711
                return getFeatureAt(i);
712 44253 jjdelcerro
            } catch (ConcurrentDataModificationException ex) {
713 46483 fdiaz
                LOG.info("ConcurrentDataModification error getting feature " + i + " of the list. Retrying reloading data. "+(featSet==null?0:featSet.hashCode()));
714 44253 jjdelcerro
                try {
715
                    reload();
716
                } catch (BaseException e) {
717 46483 fdiaz
                    LOG.warn("Error reloading data. "+(featSet==null?0:featSet.hashCode()), e);
718 44253 jjdelcerro
                    throw new RuntimeException(e);
719
                }
720
                try {
721
                    return getFeatureAt(i);
722
                } catch (Exception e) {
723 46483 fdiaz
                    LOG.warn("Error getting feature " + i + " of the list after reloading data. "+(featSet==null?0:featSet.hashCode()), e);
724 44253 jjdelcerro
                    throw new RuntimeException(e);
725
                }
726 41212 jjdelcerro
            } catch (BaseException ex) {
727 44977 jjdelcerro
                throw new RuntimeException(ex);
728 41212 jjdelcerro
            }
729
        }
730 44253 jjdelcerro
731
        @Override
732
        public Object set(int i, Object e) {
733
            return super.set(i, e);
734
        }
735
736
        @Override
737
        public Object remove(int i) {
738
            return super.remove(i);
739
        }
740
741
        @Override
742
        public boolean add(Object e) {
743
            return super.add(e);
744
        }
745 41212 jjdelcerro
    }
746 41819 fdiaz
747 41212 jjdelcerro
    private class DynObjectPagingHelperList extends PagingHelperList {
748 44977 jjdelcerro
749 44253 jjdelcerro
        @Override
750 41212 jjdelcerro
        public Object get(int i) {
751 44253 jjdelcerro
            return this.get64(i);
752
        }
753
754
        @Override
755
        public Object get64(long position) {
756 41212 jjdelcerro
            try {
757 44253 jjdelcerro
                return getDynObjectAt(position);
758
            } catch (ConcurrentDataModificationException ex) {
759 46483 fdiaz
                LOG.warn("ConcurrentDataModification error getting element " + position + " of the list. Retrying reloading data. "+(featSet==null?0:featSet.hashCode()));
760 44253 jjdelcerro
                try {
761
                    reload();
762
                } catch (BaseException e) {
763 46483 fdiaz
                    LOG.warn("Error reloading data. "+(featSet==null?0:featSet.hashCode()), e);
764 44253 jjdelcerro
                    throw new RuntimeException(e);
765
                }
766
                try {
767
                    return getDynObjectAt(position);
768
                } catch (Exception e) {
769 46483 fdiaz
                    LOG.warn("Error getting element " + position + " of the list after reloading data. "+(featSet==null?0:featSet.hashCode()), e);
770 44253 jjdelcerro
                    throw new RuntimeException(e);
771
                }
772 47431 jjdelcerro
            } catch(FeatureIndexException ex) {
773
                IndexOutOfBoundsException ioobe = new IndexOutOfBoundsException("");
774
                ioobe.initCause(ex);
775
                throw ioobe;
776 41212 jjdelcerro
            } catch (BaseException ex) {
777 44977 jjdelcerro
                throw new RuntimeException(ex);
778 41212 jjdelcerro
            }
779
        }
780 42775 jjdelcerro
781 41212 jjdelcerro
    }
782 41819 fdiaz
783 45196 jjdelcerro
    private abstract class PagingHelperList implements List, FacadeOfAFeaturePagingHelper, UnmodifiableBasicList, UnmodifiableBasicList64, Disposable {
784 41212 jjdelcerro
785 42775 jjdelcerro
        @Override
786 45196 jjdelcerro
        public void dispose() {
787
            FeaturePagingHelperImpl.this.dispose();
788
        }
789
790
        @Override
791 42775 jjdelcerro
        public FeaturePagingHelper getFeaturePagingHelper() {
792
            return FeaturePagingHelperImpl.this;
793
        }
794 44253 jjdelcerro
795
        @Override
796
        public String toString() {
797
            return String.format("..(%d %ss)...", this.size(), featureStore.getName());
798
        }
799 44977 jjdelcerro
800 44253 jjdelcerro
        @Override
801
        public long size64() {
802 45195 omartinez
            FeatureSet fset = null;
803 41212 jjdelcerro
            try {
804 45195 omartinez
                fset = getFeatureSet(false);
805
                return fset.getSize();
806 44253 jjdelcerro
            } catch (ConcurrentDataModificationException ex) {
807 46483 fdiaz
                LOG.info("ConcurrentDataModification error asking the size of the list. Retrying reloading data. "+(featSet==null?0:featSet.hashCode()));
808 44253 jjdelcerro
                try {
809
                    reload();
810
                } catch (BaseException e) {
811 46483 fdiaz
                    LOG.warn("Error reloading data. "+(featSet==null?0:featSet.hashCode()), e);
812 44253 jjdelcerro
                    throw new RuntimeException(e);
813
                }
814
                try {
815 45195 omartinez
                    fset = getFeatureSet(false);
816
                    return fset.getSize();
817 44253 jjdelcerro
                } catch (DataException e) {
818 46483 fdiaz
                    LOG.warn("Error asking the size of the list after reloading data. "+(featSet==null?0:featSet.hashCode()), e);
819 44253 jjdelcerro
                    throw new RuntimeException(e);
820
                }
821 41212 jjdelcerro
            } catch (DataException ex) {
822 44977 jjdelcerro
                throw new RuntimeException(ex);
823 41212 jjdelcerro
            }
824
        }
825
826 44253 jjdelcerro
        @Override
827
        public int size() {
828
            long sz = this.size64();
829 44977 jjdelcerro
            if (sz > Integer.MAX_VALUE) {
830 44253 jjdelcerro
                sz = Integer.MAX_VALUE;
831
            }
832
            return (int) sz;
833
        }
834
835
        @Override
836 41212 jjdelcerro
        public boolean isEmpty() {
837
            try {
838
                return getFeatureSet(false).isEmpty();
839 41819 fdiaz
            } catch (ConcurrentDataModificationException ex) {
840 46483 fdiaz
                LOG.warn("ConcurrentDataModification error asking about the emptiness of the list. Retrying reloading data. "+(featSet==null?0:featSet.hashCode()));
841 41819 fdiaz
                try {
842
                    reload();
843
                } catch (BaseException e) {
844 46483 fdiaz
                    LOG.warn("Error reloading data. "+(featSet==null?0:featSet.hashCode()), e);
845 41819 fdiaz
                    throw new RuntimeException(e);
846
                }
847
                try {
848
                    return getFeatureSet(false).isEmpty();
849 45425 jjdelcerro
                } catch (RuntimeException e) {
850
                    throw  e;
851
                } catch (Exception e) {
852 46483 fdiaz
                    LOG.warn("Error asking about the emptiness of the list after reloading data. "+(featSet==null?0:featSet.hashCode()), e);
853 41819 fdiaz
                    throw new RuntimeException(e);
854
                }
855 45425 jjdelcerro
            } catch (RuntimeException ex) {
856
                throw  ex;
857
            } catch (Exception ex) {
858 44977 jjdelcerro
                throw new RuntimeException(ex);
859 41212 jjdelcerro
            }
860
        }
861
862 44253 jjdelcerro
        @Override
863 41212 jjdelcerro
        public Iterator iterator() {
864
            try {
865
                return getFeatureSet(false).fastIterator();
866 44253 jjdelcerro
            } catch (ConcurrentDataModificationException ex) {
867 46483 fdiaz
                LOG.warn("ConcurrentDataModification error getting iterator of the list. Retrying reloading data. "+(featSet==null?0:featSet.hashCode()));
868 44253 jjdelcerro
                try {
869
                    reload();
870
                } catch (BaseException e) {
871 46483 fdiaz
                    LOG.warn("Error reloading data. "+(featSet==null?0:featSet.hashCode()), e);
872 44253 jjdelcerro
                    throw new RuntimeException(e);
873
                }
874
                try {
875
                    return getFeatureSet(false).fastIterator();
876
                } catch (DataException e) {
877 46483 fdiaz
                    LOG.warn("Error getting iterator of the list after reloading data. "+(featSet==null?0:featSet.hashCode()), e);
878 44253 jjdelcerro
                    throw new RuntimeException(e);
879
                }
880 41212 jjdelcerro
            } catch (DataException ex) {
881 44977 jjdelcerro
                throw new RuntimeException(ex);
882 41212 jjdelcerro
            }
883
        }
884
885 44253 jjdelcerro
        @Override
886 41212 jjdelcerro
        public boolean contains(Object o) {
887
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
888
        }
889
890 44253 jjdelcerro
        @Override
891 41212 jjdelcerro
        public Object[] toArray() {
892
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
893
        }
894
895 44253 jjdelcerro
        @Override
896 41212 jjdelcerro
        public Object[] toArray(Object[] ts) {
897
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
898
        }
899
900 44253 jjdelcerro
        @Override
901 41212 jjdelcerro
        public boolean add(Object e) {
902
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
903
        }
904
905 44253 jjdelcerro
        @Override
906 41212 jjdelcerro
        public boolean remove(Object o) {
907
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
908
        }
909
910 44253 jjdelcerro
        @Override
911 41212 jjdelcerro
        public boolean containsAll(Collection clctn) {
912
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
913
        }
914
915 44253 jjdelcerro
        @Override
916 41212 jjdelcerro
        public boolean addAll(Collection clctn) {
917
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
918
        }
919
920 44253 jjdelcerro
        @Override
921 41212 jjdelcerro
        public boolean addAll(int i, Collection clctn) {
922
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
923
        }
924
925 44253 jjdelcerro
        @Override
926 41212 jjdelcerro
        public boolean removeAll(Collection clctn) {
927
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
928
        }
929
930 44253 jjdelcerro
        @Override
931 41212 jjdelcerro
        public boolean retainAll(Collection clctn) {
932
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
933
        }
934
935 44253 jjdelcerro
        @Override
936 41212 jjdelcerro
        public void clear() {
937
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
938
        }
939
940 44253 jjdelcerro
        @Override
941 41212 jjdelcerro
        public Object set(int i, Object e) {
942
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
943
        }
944
945 44253 jjdelcerro
        @Override
946 41212 jjdelcerro
        public void add(int i, Object e) {
947
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
948
        }
949
950 44253 jjdelcerro
        @Override
951 41212 jjdelcerro
        public Object remove(int i) {
952
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
953
        }
954
955 44253 jjdelcerro
        @Override
956 41212 jjdelcerro
        public int indexOf(Object o) {
957
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
958
        }
959
960 44253 jjdelcerro
        @Override
961 41212 jjdelcerro
        public int lastIndexOf(Object o) {
962
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
963
        }
964
965 44253 jjdelcerro
        @Override
966 41212 jjdelcerro
        public ListIterator listIterator() {
967
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
968
        }
969
970 44253 jjdelcerro
        @Override
971 41212 jjdelcerro
        public ListIterator listIterator(int i) {
972
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
973
        }
974
975 44253 jjdelcerro
        @Override
976 41212 jjdelcerro
        public List subList(int i, int i1) {
977
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
978
        }
979 41819 fdiaz
980 44253 jjdelcerro
        @Override
981
        public List toList() {
982
            return this;
983
        }
984
985 41212 jjdelcerro
    }
986 45425 jjdelcerro
987
    @Override
988
    public long size64() {
989 45561 fdiaz
        try {
990
            return this.getTotalSize();
991
        } catch (ConcurrentDataModificationException ex) {
992 46483 fdiaz
            LOG.warn("ConcurrentDataModification error getting size of the list. Retrying reloading data. "+(featSet==null?0:featSet.hashCode()));
993 45561 fdiaz
            try {
994
                reload();
995
            } catch (BaseException e) {
996 46483 fdiaz
                LOG.warn("Error reloading data. "+(featSet==null?0:featSet.hashCode()), e);
997 45561 fdiaz
                throw new RuntimeException(e);
998
            }
999
            try {
1000
                return this.getTotalSize();
1001
            } catch (Exception e) {
1002 46483 fdiaz
                LOG.warn("Error getting size of the list after reloading data. "+(featSet==null?0:featSet.hashCode()), e);
1003 45561 fdiaz
                throw new RuntimeException(e);
1004
            }
1005
        } catch (Exception ex) {
1006
            throw new RuntimeException(ex);
1007
        }
1008 45425 jjdelcerro
    }
1009
1010
    @Override
1011
    public Feature get64(long position) {
1012
        try {
1013 45561 fdiaz
            return getFeatureAt(position);
1014
        } catch (ConcurrentDataModificationException ex) {
1015 46483 fdiaz
            LOG.warn("ConcurrentDataModification error getting element " + position + " of the list. Retrying reloading data. "+(featSet==null?0:featSet.hashCode()));
1016 45561 fdiaz
            try {
1017
                reload();
1018
            } catch (BaseException e) {
1019 46483 fdiaz
                LOG.warn("Error reloading data. "+(featSet==null?0:featSet.hashCode()), e);
1020 45561 fdiaz
                throw new RuntimeException(e);
1021
            }
1022
            try {
1023
                return getFeatureAt(position);
1024
            } catch (Exception e) {
1025 46483 fdiaz
                LOG.warn("Error getting element " + position + " of the list after reloading data. "+(featSet==null?0:featSet.hashCode()), e);
1026 45561 fdiaz
                throw new RuntimeException(e);
1027
            }
1028 45425 jjdelcerro
        } catch (BaseException ex) {
1029
            throw new RuntimeException(ex);
1030
        }
1031
    }
1032
1033
    @Override
1034
    public Iterator<Feature> iterator() {
1035
        try {
1036
            return getFeatureSet(false).fastIterator();
1037
        } catch (Exception ex) {
1038
            throw new RuntimeException(ex);
1039
        }
1040
    }
1041
1042 47198 jjdelcerro
    @Override
1043
    public String toString() {
1044
        try {
1045
            ToStringBuilder builder = new ToStringBuilder(this);
1046
            builder.append("evaluators", this.featureStore, true);
1047
            builder.append("query", this.query, true);
1048
            builder.append("selectionUp", this.selectionUp);
1049
            return builder.toString();
1050
        } catch (Exception e) {
1051
            return super.toString();
1052
        }
1053
    }
1054 40435 jjdelcerro
}