Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.file / org.gvsig.fmap.dal.file.lib / src / main / java / org / gvsig / fmap / dal / store / simplereader / SimpleReaderStoreProvider.java @ 47655

History | View | Annotate | Download (33.9 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 modify it under
7
 * the terms of the GNU General Public License as published by the Free Software
8
 * Foundation; either version 3 of the License, or (at your option) any later
9
 * version.
10
 *
11
 * This program is distributed in the hope that it will be useful, but WITHOUT
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14
 * details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with
17
 * this program; if not, write to the Free Software Foundation, Inc., 51
18
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
 *
20
 * For any additional information, do not hesitate to contact us at info AT
21
 * gvsig.com, or visit our website www.gvsig.com.
22
 */
23
package org.gvsig.fmap.dal.store.simplereader;
24

    
25
import java.io.Closeable;
26
import java.io.File;
27
import java.io.IOException;
28
import java.io.InputStreamReader;
29
import java.io.Reader;
30
import java.net.URI;
31
import java.net.URL;
32
import java.nio.charset.StandardCharsets;
33
import java.util.ArrayList;
34
import java.util.HashMap;
35
import java.util.Iterator;
36
import java.util.List;
37
import java.util.Objects;
38
import org.apache.commons.io.FileUtils;
39
import org.apache.commons.io.FilenameUtils;
40
import org.apache.commons.io.IOUtils;
41
import org.cresques.cts.IProjection;
42
import org.gvsig.fmap.dal.DALLocator;
43
import org.gvsig.fmap.dal.DataManager;
44
import org.gvsig.fmap.dal.DataServerExplorer;
45
import org.gvsig.fmap.dal.DataStore;
46
import org.gvsig.fmap.dal.DataStoreNotification;
47
import org.gvsig.fmap.dal.DataTypes;
48
import org.gvsig.fmap.dal.exception.CloseException;
49
import org.gvsig.fmap.dal.exception.DataException;
50
import org.gvsig.fmap.dal.exception.InitializeException;
51
import org.gvsig.fmap.dal.exception.OpenException;
52
import org.gvsig.fmap.dal.exception.ReadException;
53
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
54
import org.gvsig.fmap.dal.feature.EditableFeatureType;
55
import org.gvsig.fmap.dal.feature.Feature;
56
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
57
import org.gvsig.fmap.dal.feature.FeatureQuery;
58
import org.gvsig.fmap.dal.feature.FeatureStore;
59
import org.gvsig.fmap.dal.feature.FeatureType;
60
import org.gvsig.fmap.dal.feature.exception.CreateFeatureException;
61
import org.gvsig.fmap.dal.feature.exception.PerformEditingException;
62
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
63
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
64
import org.gvsig.fmap.dal.feature.spi.FeatureSetProvider;
65
import org.gvsig.fmap.dal.feature.spi.memory.AbstractMemoryStoreProvider;
66
import org.gvsig.fmap.dal.resource.file.FileResource;
67
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
68
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
69
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorer;
70
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorerParameters;
71
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
72
import org.gvsig.fmap.dal.store.simplereader.simplereaders.AbstractSimpleReader;
73
import org.gvsig.fmap.dal.store.simplereader.simplereaders.SimpleReader;
74
import org.gvsig.fmap.geom.Geometry;
75
import org.gvsig.fmap.geom.GeometryLocator;
76
import org.gvsig.fmap.geom.GeometryManager;
77
import org.gvsig.fmap.geom.SpatialIndex;
78
import org.gvsig.fmap.geom.SpatialIndexFactory;
79
import org.gvsig.fmap.geom.primitive.Envelope;
80
import org.gvsig.fmap.geom.primitive.Point;
81
import org.gvsig.tools.ToolsLocator;
82
import org.gvsig.tools.dataTypes.Coercion;
83
import org.gvsig.tools.dataTypes.CoercionContext;
84
import org.gvsig.tools.dispose.DisposableIterator;
85
import org.gvsig.tools.dispose.DisposeUtils;
86
import org.gvsig.tools.dynobject.DynObject;
87
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
88
import org.gvsig.tools.evaluator.AbstractEvaluator;
89
import org.gvsig.tools.evaluator.EvaluatorData;
90
import org.gvsig.tools.evaluator.EvaluatorException;
91
import org.gvsig.tools.exception.BaseException;
92
import org.gvsig.tools.exception.NotYetImplemented;
93
import org.gvsig.tools.i18n.I18nManager;
94
import org.gvsig.tools.persistence.PersistentState;
95
import org.gvsig.tools.persistence.exception.PersistenceException;
96
import org.gvsig.tools.task.SimpleTaskStatus;
97
import org.gvsig.tools.task.TaskStatusManager;
98
import org.gvsig.tools.task.UserCancelTaskException;
99
import org.gvsig.tools.util.GetItemWithSize64;
100
import org.gvsig.tools.visitor.VisitCanceledException;
101
import org.gvsig.tools.visitor.Visitor;
102
import org.slf4j.Logger;
103
import org.slf4j.LoggerFactory;
104

    
105
@SuppressWarnings("UseSpecificCatch")
106
public abstract class SimpleReaderStoreProvider extends AbstractMemoryStoreProvider implements
107
        ResourceConsumer {
108

    
109
    protected static final Logger LOGGER = LoggerFactory.getLogger(SimpleReaderStoreProvider.class);
110

    
111
//    public static final String NAME = DataStore.CSV_PROVIDER_NAME;
112
//    public static final String DESCRIPTION = "CSV file";
113
//
114
//    public static final String METADATA_DEFINITION_NAME = NAME;
115

    
116
    protected final ResourceProvider resource;
117

    
118
    protected long counterNewsOIDs = 0;
119
    protected Envelope envelope;
120
    protected boolean need_calculate_envelope = false;
121
    protected final SimpleTaskStatus taskStatus;
122
    protected FeatureType featureType;
123
    protected GetItemWithSize64<List<String>> virtualrows;
124
    protected RowToFeatureTranslator rowToFeatureTranslator;
125
    protected SpatialIndex spatialIndex;
126
    
127
    @SuppressWarnings({"OverridableMethodCallInConstructor", "LeakingThisInConstructor"})
128
    public SimpleReaderStoreProvider(
129
            SimpleReaderStoreParameters parameters,
130
            DataStoreProviderServices storeServices,
131
            DynObject metadata
132
        ) throws InitializeException {
133
        super(
134
                parameters,
135
                storeServices,
136
                metadata
137
        );
138
        TaskStatusManager manager = ToolsLocator.getTaskStatusManager();
139
        this.taskStatus = manager.createDefaultSimpleTaskStatus("CSV");
140
        this.taskStatus.setAutoremove(true);
141

    
142
        counterNewsOIDs = 0;
143

    
144
        File file = getSimpleReaderParameters().getFile();
145
        resource = this.createResource(
146
                FileResource.NAME,
147
                new Object[]{file.getAbsolutePath()}
148
        );
149

    
150
        resource.addConsumer(this);
151

    
152
        initializeFeatureTypes();
153
    }
154

    
155
    private SimpleReaderStoreParameters getSimpleReaderParameters() {
156
        return (SimpleReaderStoreParameters) this.getParameters();
157
    }
158

    
159
    @Override
160
    public abstract String getProviderName();
161

    
162
    @Override
163
    public boolean allowWrite() {
164
        return false;
165
    }
166

    
167
    protected String getFullFileName() {
168
        // Usar solo para mostrar mensajes en el logger.
169
        String s;
170
        try {
171
            s = getSimpleReaderParameters().getFile().getAbsolutePath();
172
        } catch (Exception e2) {
173
            s = "(unknow)";
174
        }
175
        return s;
176
    }
177

    
178
    @Override
179
    public void open() throws OpenException {
180
        if (this.data != null) {
181
            return;
182
        }
183
        this.data = new ArrayList<>();
184
        resource.setData(new HashMap());
185
        counterNewsOIDs = 0;
186
        try {
187
            loadFeatures();
188
        } catch (RuntimeException e) {
189
            LOGGER.debug("Can't load features from CSV '" + getFullFileName() + "'.", e);
190
            throw e;
191
        } catch (Exception e) {
192
            LOGGER.debug("Can't load features from CSV '" + getFullFileName() + "'.", e);
193
            throw new RuntimeException(e);
194
        }
195
    }
196

    
197
    @Override
198
    public DataServerExplorer getExplorer() throws ReadException {
199
        DataManager manager = DALLocator.getDataManager();
200
        FilesystemServerExplorerParameters params;
201
        try {
202
            params = (FilesystemServerExplorerParameters) manager
203
                    .createServerExplorerParameters(FilesystemServerExplorer.NAME);
204
            params.setRoot(this.getSimpleReaderParameters().getFile().getParent());
205
            return manager.openServerExplorer(FilesystemServerExplorer.NAME, params);
206
        } catch (Exception e) {
207
            throw new ReadException(this.getProviderName(), e);
208
        }
209

    
210
    }
211

    
212
    @Override
213
    @SuppressWarnings("Convert2Lambda")
214
    public void performChanges(Iterator deleteds, Iterator inserteds, Iterator updateds, Iterator originalFeatureTypesUpdated) throws PerformEditingException {
215
        throw new UnsupportedOperationException();
216
    }
217

    
218
    @Override
219
    public boolean closeResourceRequested(ResourceProvider resource) {
220
        return true;
221
    }
222

    
223
    @Override
224
    public int getOIDType() {
225
        return DataTypes.LONG;
226
    }
227

    
228
    @Override
229
    public boolean supportsAppendMode() {
230
        return false;
231
    }
232

    
233
    @Override
234
    @SuppressWarnings("Convert2Lambda")
235
    public void append(final FeatureProvider featureProvider) {
236
        throw new UnsupportedOperationException();
237
    }
238

    
239
    @Override
240
    @SuppressWarnings("Convert2Lambda")
241
    public void beginAppend() throws DataException {
242
        throw new UnsupportedOperationException();
243
    }
244

    
245
    @Override
246
    @SuppressWarnings("Convert2Lambda")
247
    public void endAppend() {
248
        throw new UnsupportedOperationException();
249
    }
250

    
251
    public void saveToState(PersistentState state) throws PersistenceException {
252
        throw new NotYetImplemented();
253
    }
254

    
255
    public void loadFromState(PersistentState state) throws PersistenceException {
256
        throw new NotYetImplemented();
257
    }
258

    
259
    @Override
260
    public Object createNewOID() {
261
        return counterNewsOIDs++;
262
    }
263

    
264
    protected void initializeFeatureTypes() throws InitializeException {
265
        try {
266
            this.open();
267
        } catch (OpenException e) {
268
            throw new InitializeException(this.getProviderName(), e);
269
        }
270
    }
271

    
272
    @Override
273
    @SuppressWarnings("Convert2Lambda")
274
    public Envelope getEnvelope() throws DataException {
275
        this.open();
276
        if (this.envelope != null) {
277
            return this.envelope;
278
        }
279
        this.envelope = bboxFileLoad();
280
        if (this.envelope != null) {
281
            return this.envelope;
282
        }
283
        if (!this.need_calculate_envelope) {
284
            return null;
285
        }
286
        try {
287
            I18nManager i18n = ToolsLocator.getI18nManager();
288
            this.taskStatus.add();
289
            this.taskStatus.message(i18n.getTranslation("_Calculating_envelope"));
290
            FeatureStore fs = this.getFeatureStore();
291
            FeatureType ft = fs.getDefaultFeatureType();
292
            FeatureAttributeDescriptor fad = ft.getAttributeDescriptor(ft.getDefaultGeometryAttributeIndex());
293
            this.taskStatus.setRangeOfValues(0, fs.getFeatureCount());
294
            this.envelope = GeometryLocator.getGeometryManager().createEnvelope(fad.getGeomType().getSubType());
295
            fs.accept(new Visitor() {
296
                @Override
297
                public void visit(Object obj) throws VisitCanceledException, BaseException {
298
                    taskStatus.incrementCurrentValue();
299
                    if(taskStatus.isCancellationRequested()){
300
                        taskStatus.cancel();
301
                        throw new VisitCanceledException();
302
                    }
303
                    Feature f = (Feature) obj;
304
                    Geometry geom = f.getDefaultGeometry();
305
                    if (geom != null) {
306
                        try {
307
                            Envelope env = geom.getEnvelope();
308
                            envelope.add(env);
309
                        } catch(Exception ex) {
310
                            LOGGER.warn("Can't calculate envelop of geometry in feature '"+Objects.toString(f.getReference())+"'.",ex);
311
                        }
312
                    }
313
                }
314
            });
315
            bboxFileSave(envelope);
316
            taskStatus.terminate();
317
        } catch (VisitCanceledException e) {
318
            return null;
319
        } catch (BaseException e) {
320
            taskStatus.abort();
321
            LOGGER.warn("Can't calculate the envelope of CSV file '" + this.getFullName() + "'.", e);
322
            return null;
323
        }
324

    
325
        this.need_calculate_envelope = false;
326
        return this.envelope;
327
    }
328

    
329
    @Override
330
    public Object getDynValue(String name) throws DynFieldNotFoundException {
331
        if (DataStore.METADATA_ENVELOPE.equalsIgnoreCase(name)) {
332
            try {
333
                return this.getEnvelope();
334
            } catch (DataException e) {
335
                return null;
336
            }
337
        } else {
338
            if (DataStore.METADATA_CRS.equalsIgnoreCase(name)) {
339
                IProjection pro = SimpleReaderStoreParameters.getCRS(this.getSimpleReaderParameters());
340
                if (pro != null) {
341
                    return pro;
342
                }
343
            }
344
        }
345
        return super.getDynValue(name);
346
    }
347

    
348
    @Override
349
    public void resourceChanged(ResourceProvider resource) {
350
        this.getStoreServices().notifyChange(
351
                DataStoreNotification.RESOURCE_CHANGED,
352
                resource);
353
    }
354

    
355
    @Override
356
    public Object getSourceId() {
357
        return this.getSimpleReaderParameters().getFile();
358
    }
359

    
360
    @Override
361
    public String getName() {
362
        String name = this.getSimpleReaderParameters().getFile().getName();
363
        return FilenameUtils.getBaseName(name);
364
    }
365

    
366
    @Override
367
    public String getFullName() {
368
        return this.getSimpleReaderParameters().getFile().getAbsolutePath();
369
    }
370

    
371
    @Override
372
    public ResourceProvider getResource() {
373
        return resource;
374
    }
375

    
376
    private boolean isEmpty(String s) {
377
        if (s == null) {
378
            return true;
379
        }
380
        return s.trim().length() == 0;
381
    }
382

    
383
    private void init(SimpleReaderStoreParameters parameters, DataStoreProviderServices storeServices) {
384
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
385
    }
386

    
387
    static class ToPointEvaluaror extends AbstractEvaluator {
388

    
389
        private static final Logger logger = LoggerFactory.getLogger(ToPointEvaluaror.class);
390

    
391
        private GeometryManager geommgr = null;
392
        private String xname = null;
393
        private String yname = null;
394
        private String zname = null;
395
        private final Coercion toDouble;
396
        private int errorcount = 0;
397

    
398
        ToPointEvaluaror(String[] pointDimensionNames) {
399
            this.xname = pointDimensionNames[0];
400
            this.yname = pointDimensionNames[1];
401
            if (pointDimensionNames.length > 2) {
402
                this.zname = pointDimensionNames[2];
403
            }
404
            this.geommgr = GeometryLocator.getGeometryManager();
405
            this.toDouble = ToolsLocator.getDataTypesManager().getCoercion(DataTypes.DOUBLE);
406
        }
407

    
408
        @Override
409
        public Object evaluate(EvaluatorData data) throws EvaluatorException {
410
            try {
411
                double x = ((Double) toDouble.coerce(data.getDataValue(xname)));
412
                double y = ((Double) toDouble.coerce(data.getDataValue(yname)));
413
                Point point = geommgr.createPoint(x, y, Geometry.SUBTYPES.GEOM3D);
414
                if (zname != null) {
415
                    double z = ((Double) toDouble.coerce(data.getDataValue(zname)));
416
                    point.setCoordinateAt(2, z);
417
                }
418
                return point;
419
            } catch (Exception ex) {
420
                if (++errorcount < 5) {
421
                    logger.warn("[" + errorcount + "] Can't create point in CSV provider. XNAME='"
422
                            + xname + "', YNAME='" + yname + "', ZNAME='" + zname + "', data=" + data.toString());
423
                }
424
                return null;
425
            }
426
        }
427

    
428
        @Override
429
        public String getName() {
430
            return "ToPointEvaluaror";
431
        }
432

    
433
    }
434

    
435
    public static class RowToFeatureTranslator {
436

    
437
        private Coercion coercion[];
438
        private CoercionContext coercionContext[];
439
        private int sizes[];
440
        private String[] names;
441
        private final boolean ignore_errors;
442
        private long count_errors;
443
        private FeatureType csvFeatureType;
444

    
445
        public RowToFeatureTranslator(boolean ignore_errors) {
446
            this.ignore_errors = ignore_errors;
447
            this.count_errors = 0;
448
        }
449

    
450
        public int getColumnSize(int column) {
451
            return this.sizes[column];
452
        }
453

    
454
        public void initialize(FeatureType ftype) {
455
            this.csvFeatureType = ftype;
456
            int columns = this.csvFeatureType.size();
457
            this.names = new String[columns];
458
            this.coercion = new Coercion[columns];
459
            this.coercionContext = new CoercionContext[columns];
460
            this.sizes = new int[columns];
461
            int index = 0;
462
            for (int i = 0; i < this.csvFeatureType.size(); i++) {
463
                FeatureAttributeDescriptor ad = this.csvFeatureType.getAttributeDescriptor(i);
464
                names[i] = null;
465
                if( ad.isComputed() ) {
466
                    continue;
467
                }
468
                names[index] = ad.getName();
469
                coercion[index] = ad.getCoercion();
470
                coercionContext[index] = ad.getCoercionContext();
471
                sizes[index] = ad.getSize();
472
                index++;
473
            }
474
        }
475

    
476
        public void translate(long rowindex, List<String> row, FeatureProvider feature) throws Exception {
477

    
478
            feature.setOID(rowindex);
479
            for (int i = 0; i < names.length; i++) {
480
                String name = names[i];
481
                if( name == null ) {
482
                    break;
483
                }
484
                Object rawvalue = row.get(i);
485
                try {
486
                    Object value = null;
487
                    if (coercion[i] != null) {
488
                        value = coercion[i].coerce(rawvalue, coercionContext[i]);
489
                    }
490
                    int findex = feature.getType().getIndex(name);
491
                    if( findex>=0 ) {
492
                        // Ojo que puede que se este filtrando el featuretype y no 
493
                        // tenga todos los atributos, por ejemplo al pintar la vista.
494
                        feature.set(findex, value);
495
                    }
496
                    if (sizes[i] >= 0
497
                            && (value instanceof String || value instanceof URL
498
                            || value instanceof URI || value instanceof File)) {
499
                        int x = value.toString().length();
500
                        if (sizes[i] < x) {
501
                            sizes[i] = x;
502
                        }
503
                    }
504
                } catch (Exception ex) {
505
                    if (!ignore_errors) {
506
                        throw ex;
507
                    }
508
                    if (count_errors++ < 10) {
509
                        LOGGER.warn("Can't load value of attribute " + name +"/" +i+" in row " + rowindex + ".", ex);
510
                    }
511
                    if (count_errors == 10) {
512
                        LOGGER.info("Too many errors, suppress messages.");
513
                    }
514
                }
515
            }
516
        }
517
    }
518

    
519
    protected abstract SimpleReaderFeatureTypeLoader getFeatureTypeLoader();
520
    
521
    protected void loadFeatures() {
522
        InputStreamReader in = null;
523
        SimpleReader reader = null;
524
        try {
525
            taskStatus.setTitle("CSV "+this.getName());
526
            taskStatus.add();
527
//            boolean ignore_errors = CSVStoreParameters.getIgnoreErrors(getCSVParameters());
528

    
529
            // Initialize the feature types
530
            EditableFeatureType edftype = getStoreServices().createFeatureType(this.getName());
531
            SimpleReaderFeatureTypeLoader featureTypeLoader = getFeatureTypeLoader();
532
            featureTypeLoader.loadFeatureType(edftype, taskStatus);
533
            FeatureType ftype = edftype.getNotEditableCopy();
534
            this.setFeatureType(ftype);
535

    
536
            in = SimpleReaderUtils.openFile(
537
                    this.getSimpleReaderParameters().getFile(),
538
                    SimpleReaderStoreParameters.getCharset(this.getSimpleReaderParameters())
539
            );
540
            reader = getSimpleReader(getSimpleReaderParameters(), in);
541
            if (featureTypeLoader.isFirstLineHeader()) {
542
                reader.getHeader(); // Skip and ignore the header of file
543
            }
544
            this.rowToFeatureTranslator = new RowToFeatureTranslator(
545
                    SimpleReaderStoreParameters.getIgnoreErrors(getSimpleReaderParameters())
546
            );
547
            this.rowToFeatureTranslator.initialize(ftype);
548
            if (ftype.getDefaultGeometryAttributeName() != null) {
549
                this.need_calculate_envelope = true;
550
            }
551
            I18nManager i18n = ToolsLocator.getI18nManager();
552
            taskStatus.message(i18n.getTranslation("_Loading"));
553

    
554
            if(this.virtualrows != null && this.virtualrows instanceof Closeable){
555
                IOUtils.closeQuietly((Closeable) this.virtualrows);
556
                this.virtualrows = null;
557
            }
558
            
559
            this.virtualrows = ((AbstractSimpleReader) reader).getVirtualRows(this.taskStatus);
560
            if(this.taskStatus.isCancellationRequested()){
561
                throw new UserCancelTaskException();
562
            }
563
            if (this.virtualrows == null) {
564

    
565
                taskStatus.message(i18n.getTranslation("_Loading"));
566
                taskStatus.setIndeterminate();
567

    
568
                List<String> row = reader.read();
569

    
570
                int skipLines = SimpleReaderStoreParameters.getSkipLines(getSimpleReaderParameters());
571
                if (skipLines > 0) {
572
                    row = reader.skip(skipLines);
573
                }
574
                int limit = SimpleReaderStoreParameters.getLimit(getSimpleReaderParameters());
575
                while (row != null) {
576
                    taskStatus.incrementCurrentValue();
577
                    if( taskStatus.isCancellationRequested() ) {
578
                        taskStatus.cancel();
579
                        break;
580
                    }
581
                    FeatureProvider feature = this.createFeatureProvider(ftype);
582
                    this.rowToFeatureTranslator.translate(reader.getLine(), row, feature);
583

    
584
                    this.addFeatureProvider(feature);
585
                    if (limit > 0) {
586
                        if (limit < this.data.size()) {
587
                            break;
588
                        }
589
                    }
590
                    row = reader.read();
591
                }
592
                for (int i = 0; i < ftype.size(); i++) {
593
                    if (this.rowToFeatureTranslator.getColumnSize(i) > 0) {
594
//                    if (sizes[i] > 0) {
595
                        EditableFeatureAttributeDescriptor efad = ((EditableFeatureAttributeDescriptor) edftype.getAttributeDescriptor(i));
596
//                        efad.setSize(sizes[i]);
597
                        efad.setSize(this.rowToFeatureTranslator.getColumnSize(i));
598
                    }
599
                }
600
                // Volvemos a asignar al store el featuretype, ya que puede
601
                // haber cambiado.
602
                ftype = edftype.getNotEditableCopy();
603
                this.setFeatureType(ftype);
604
            } else {
605
                this.loadOrCreateSpatialIndex();
606
            }
607
            if( taskStatus.isRunning() ) {
608
                taskStatus.terminate();
609
            }
610
        } catch (UserCancelTaskException ex) {
611
            this.taskStatus.cancel();
612
            throw ex;
613
        } catch (Throwable ex) {
614
            taskStatus.abort();
615
            int lineno = 0;
616
            if (reader != null) {
617
                lineno = reader.getLine();
618
            }
619
            throw new RuntimeException("Problems reading file '" + getFullFileName() + "' near record " + lineno + ".", ex);
620

    
621
        } finally {
622
            if (reader != null) {
623
                try {
624
                    reader.close();
625
                } catch (Exception ex) {
626
                    // Do nothing
627
                }
628
//                reader = null;
629
            }
630
            if (in != null) {
631
                try {
632
                    in.close();
633
                } catch (Exception ex) {
634
                    // Do nothing
635
                }
636
//                in = null;
637
            }
638
            taskStatus.remove();
639
        }
640
    }
641

    
642
    @Override
643
    public void fixFeatureTypeFromParameters() {
644
        if(mustFixFeatureType() && featureType != null){
645
            this.setFeatureType(featureType);
646
        }
647
    }
648
    
649
    protected boolean mustFixFeatureType() {
650
        return false;
651
    }
652

    
653
    private void setFeatureType(FeatureType ftype) {
654
        try {
655
            List<FeatureType> ftypes = new ArrayList<>();
656
            ftypes.add(ftype);
657
            this.featureType = ftype;
658
            if(this.getStoreServices().getDefaultFeatureType() == null){
659
                this.getStoreServices().setFeatureTypes(ftypes, ftype);
660
                return;
661
            }
662
            if(mustFixFeatureType()){
663
                this.getStoreServices().setFeatureTypes(ftypes, ftype);
664
            }
665
        } catch (DataException ex) {
666
            LOGGER.warn("Cant set feature type", ex);
667
        }
668
    }
669

    
670
    @Override
671
    public FeatureSetProvider createSet(FeatureQuery query, FeatureType providerFeatureType, FeatureType featureType)
672
            throws DataException {
673
        this.open();
674
        if (this.virtualrows == null) {
675
            return super.createSet(query, providerFeatureType, featureType);
676
        }
677
        return new SimpleReaderSetProvider(this, query, providerFeatureType, featureType);
678
    }
679

    
680
    @Override
681
    public FeatureSetProvider createSet(FeatureQuery query, FeatureType featureType)
682
            throws DataException {
683
        this.open();
684
        if (this.virtualrows == null) {
685
            return super.createSet(query, featureType);
686
        }
687
        return new SimpleReaderSetProvider(this, query, featureType, featureType);
688
    }
689

    
690
    public List<String> getRowByIndex(long index) {
691
        try {
692
            this.open();
693
        } catch(Exception ex) {
694
            throw new RuntimeException("Can't get row by index", ex);
695
        }
696
        if (this.virtualrows == null) {
697
            return null;
698
        }
699
        List<String> line = this.virtualrows.get64(index);
700
        return line;
701
    }
702

    
703
    public RowToFeatureTranslator getRowToFeatureTranslator() {
704
        if (this.rowToFeatureTranslator == null) {
705
            boolean ignore_errors = SimpleReaderStoreParameters.getIgnoreErrors(getSimpleReaderParameters());
706
            this.rowToFeatureTranslator = new RowToFeatureTranslator(ignore_errors);
707
            this.rowToFeatureTranslator.initialize(featureType);
708
        }
709
        return this.rowToFeatureTranslator;
710
    }
711

    
712
    @Override
713
    public long getFeatureCount() throws DataException {
714
        this.open();
715
        if (this.virtualrows == null) {
716
            return super.getFeatureCount();
717
        }
718
        return this.virtualrows.size64();
719
    }
720

    
721
    @Override
722
    public long getDataSize() throws DataException {
723
        this.open();
724
        if (this.virtualrows == null) {
725
            return super.getDataSize();
726
        }
727
        return this.virtualrows.size64();
728
    }
729

    
730
    @Override
731
    protected FeatureProvider internalGetFeatureProviderByReference(
732
            FeatureReferenceProviderServices reference) throws DataException {
733
        this.open();
734
        if (this.virtualrows == null) {
735
            return super.internalGetFeatureProviderByReference(reference);
736
        }
737
        int oid = ((Long) reference.getOID()).intValue();
738
        RowToFeatureTranslator translator = getRowToFeatureTranslator();
739
        FeatureProvider feature = this.createFeatureProvider(this.featureType);
740
        try {
741
            translator.translate(oid, this.virtualrows.get64(oid), feature);
742
        } catch (Exception ex) {
743
            throw new CreateFeatureException(ex, this.getName());
744
        }
745
        return feature;
746
    }
747

    
748
    @Override
749
    protected void doDispose() throws BaseException {
750
        super.doDispose();
751
        if (this.virtualrows != null && this.virtualrows instanceof Closeable) {
752
            IOUtils.closeQuietly((Closeable) this.virtualrows);
753
            this.virtualrows = null;
754
        }
755
    }
756
    
757
    @Override
758
     public void refresh() throws OpenException {
759
        try {
760
            this.close();
761
        } catch (CloseException e) {
762
            throw new OpenException(this.getProviderName(), e);
763
        }
764
        this.open();
765
    }
766

    
767
    @Override
768
    public void close() throws CloseException {
769
        super.close(); //To change body of generated methods, choose Tools | Templates.
770
        this.data = null;
771
        if(this.virtualrows != null && this.virtualrows instanceof Closeable){
772
            IOUtils.closeQuietly((Closeable) this.virtualrows);
773
            this.virtualrows = null;
774
            this.envelope = null;
775
            this.spatialIndex = null;
776
        }
777
        
778
    }
779
     
780
    
781
    private void loadOrCreateSpatialIndex() {
782
        FeatureSetProvider set = null;
783
        DisposableIterator<FeatureProvider> it = null;
784
        try {
785
            if( this.virtualrows == null ) {
786
                return;
787
            }
788
            FeatureAttributeDescriptor geomdesc = this.featureType.getDefaultGeometryAttribute();
789
            if( geomdesc == null ) {
790
                return;
791
            }
792
//            String indexTypeName = "MVRTree";
793
//            String extname = "mvtree";
794
            String indexTypeName = GeometryManager.SPATIALINDEX_DEFAULT_QUADTREE;
795
            String extname = "qtree";
796
            
797
            this.envelope = bboxFileLoad();
798
            File indexfile = this.getAuxFile(extname); 
799
            boolean createIndex = !indexfile.exists();
800

    
801
            GeometryManager geomManager = GeometryLocator.getGeometryManager();
802
            SpatialIndexFactory indexfactory = geomManager.getSpatialIndexFactory(indexTypeName);
803
            DynObject params = indexfactory.createParameters();
804
            params.setDynValue("file", indexfile);
805
            SpatialIndex index = geomManager.createSpatialIndex(indexTypeName, params);
806
            if( createIndex ) { 
807
                I18nManager i18n = ToolsLocator.getI18nManager();
808
                this.taskStatus.add();
809
                taskStatus.message(i18n.getTranslation("_Creating_spatial_index"));
810
                taskStatus.setRangeOfValues(0, this.virtualrows.size64());
811
                taskStatus.setCurValue(0);
812
                Envelope theEnvelope = geomManager.createEnvelope(Geometry.SUBTYPES.GEOM2D);
813
                set = this.createSet(null, featureType);
814
                it = set.fastIterator();
815
                while( it.hasNext() ) {
816
                    taskStatus.incrementCurrentValue();
817
                    if( taskStatus.isCancellationRequested() ) {
818
                        taskStatus.cancel();
819
                        LOGGER.info("Spatial index creation cancelled ("+getFullFileName()+")");
820
                        break;
821
                    }
822
                    FeatureProvider f = it.next();
823
                    if( f == null ) {
824
                        continue;
825
                    }
826
                    Object oid = null;
827
                    try {
828
                        oid = f.getOID();
829
                        Geometry geom = (Geometry) f.get(geomdesc.getName());
830
                        if(geom!= null){
831
                            index.insert(geom, oid);
832
                            theEnvelope.add(geom);
833
                        }
834
                    } catch(Throwable ex) {
835
                        LOGGER.debug("Can't insert feature '"+Objects.toString(oid)+"' in spatial index.",ex);
836
                    }
837
                }
838
                taskStatus.message(i18n.getTranslation("_Saving_spatial_index"));
839
                taskStatus.setIndeterminate();
840
                index.flush();
841
                if(!theEnvelope.isEmpty()){
842
                    bboxFileSave(theEnvelope);
843
                }
844
                taskStatus.terminate();
845
                this.envelope = theEnvelope;
846
            }
847
            this.spatialIndex = index;
848
        } catch (Exception ex) {
849
            taskStatus.abort();
850
            LOGGER.warn("Can't create spatial index.",ex);
851
        } finally {
852
            DisposeUtils.disposeQuietly(it);
853
            DisposeUtils.disposeQuietly(set);
854
            taskStatus.remove();
855
        }
856
    }
857

    
858
    public File getAuxFile(String extension) {
859
        File data_file = SimpleReaderStoreParameters.getFile(this.getSimpleReaderParameters());
860
        if (data_file == null){
861
            return null;
862
        }
863
        File index_file = new File(FilenameUtils.removeExtension(data_file.getAbsolutePath()) + "." + extension);
864
        return index_file;
865
    }
866

    
867
    public SpatialIndex getSpatialIndex() {
868
        return spatialIndex;
869
    }
870

    
871
    protected void bboxFileSave(Envelope envelope) {
872
        File bboxfile = this.getAuxFile("bbox");
873
        bboxFileSave(bboxfile, envelope);
874
    }
875
    
876
    protected void bboxFileSave(File bboxfile, Envelope envelope) {
877
        if( envelope == null ) {
878
            bboxfile.delete();
879
            return;
880
        }
881
        try {
882
            FileUtils.write(
883
                    bboxfile, 
884
                    envelope.getBox2D().convertToWKTQuietly(), 
885
                    StandardCharsets.UTF_8
886
            );
887
        } catch(Exception ex) {
888
            LOGGER.warn("Can't write bbox file '"+Objects.toString(bboxfile)+"'.",ex);
889
        }
890
    }
891
    
892
    protected Envelope bboxFileLoad() {
893
        File bboxfile = this.getAuxFile("bbox");
894
        return bboxFileLoad(bboxfile);
895
    }
896
    
897
    protected Envelope bboxFileLoad(File bboxfile) {
898
        try {
899
            if( bboxfile.exists() ) {
900
                GeometryManager geomManager = GeometryLocator.getGeometryManager();
901
                String wkt = FileUtils.readFileToString(bboxfile, StandardCharsets.UTF_8);                    
902
                Geometry geom = geomManager.createFrom(wkt);
903
                if( geom!=null ) {
904
                    return geom.getEnvelope();
905
                }
906
            }
907
        } catch(Exception ex) {
908
            LOGGER.warn("Can't load bbox file",ex);
909
        }
910
        return null;
911
    }
912
    
913
    protected abstract SimpleReader getSimpleReader(SimpleReaderStoreParameters parameters, Reader in) throws IOException ;//{
914
//        return CSVUtils.getSimpleReader(getSimpleReaderParameters(), in);
915
//    }
916
    
917
}