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.csv / src / main / java / org / gvsig / fmap / dal / store / simplereader / SimpleReaderStoreProvider.java @ 47638

History | View | Annotate | Download (35 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.util.GetItemWithSize64;
99
import org.gvsig.tools.visitor.VisitCanceledException;
100
import org.gvsig.tools.visitor.Visitor;
101
import org.slf4j.Logger;
102
import org.slf4j.LoggerFactory;
103

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

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

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

    
115
    protected final ResourceProvider resource;
116

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

    
141
        counterNewsOIDs = 0;
142

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

    
149
        resource.addConsumer(this);
150

    
151
        initializeFeatureTypes();
152
    }
153

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

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

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

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

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

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

    
209
    }
210

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
386
    static class ToPointEvaluaror extends AbstractEvaluator {
387

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

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

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

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

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

    
432
    }
433

    
434
    public static class RowToFeatureTranslator {
435

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

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

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

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

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

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

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

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

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

    
553
            if(this.virtualrows != null && this.virtualrows instanceof Closeable){
554
                IOUtils.closeQuietly((Closeable) this.virtualrows);
555
                this.virtualrows = null;
556
            }
557
            
558
            this.virtualrows = ((AbstractSimpleReader) reader).getVirtualRows(this.taskStatus);
559
            if (this.virtualrows == null) {
560

    
561
                List<String> row = reader.read();
562

    
563
                int skipLines = SimpleReaderStoreParameters.getSkipLines(getSimpleReaderParameters());
564
                if (skipLines > 0) {
565
                    row = reader.skip(skipLines);
566
                }
567
                int limit = SimpleReaderStoreParameters.getLimit(getSimpleReaderParameters());
568
                while (row != null) {
569
                    taskStatus.incrementCurrentValue();
570
                    if( taskStatus.isCancellationRequested() ) {
571
                        taskStatus.cancel();
572
                        break;
573
                    }
574
                    FeatureProvider feature = this.createFeatureProvider(ftype);
575
                    this.rowToFeatureTranslator.translate(reader.getLine(), row, feature);
576

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

    
611
        } finally {
612
            if (reader != null) {
613
                try {
614
                    reader.close();
615
                } catch (Exception ex) {
616
                    // Do nothing
617
                }
618
//                reader = null;
619
            }
620
            if (in != null) {
621
                try {
622
                    in.close();
623
                } catch (Exception ex) {
624
                    // Do nothing
625
                }
626
//                in = null;
627
            }
628
            taskStatus.remove();
629
        }
630
    }
631

    
632
    @Override
633
    public void fixFeatureTypeFromParameters() {
634
        if(mustFixFeatureType() && featureType != null){
635
            this.setFeatureType(featureType);
636
        }
637
    }
638
    
639
    protected boolean mustFixFeatureType() {
640
        //Este m?todo lo debe sobreescribir el CSV
641
//        try {
642
//            String param_types_def = CSVStoreParameters.getRawFieldTypes(this.getParameters());
643
//            String[] pointDimensionNames = CSVStoreParameters.getPointDimensionNames(this.getParameters());
644
//            String geometry_column = CSVStoreParameters.getGeometryColumn(this.getParameters());
645
//            
646
//            
647
//            FeatureType dalFeatureType = this.getStoreServices().getDefaultFeatureType();
648
//            if (StringUtils.isNotBlank(geometry_column)){
649
//                FeatureAttributeDescriptor attr = dalFeatureType.getAttributeDescriptor(geometry_column);
650
//                if(attr == null || attr.getType() !=  DataTypes.GEOMETRY){
651
//                    return true;
652
//                }
653
//            }
654
//            if (StringUtils.isNotBlank(param_types_def)
655
//                    || pointDimensionNames != null) {
656
//                for (FeatureAttributeDescriptor dalAttr : dalFeatureType) {
657
//                    if(dalAttr.isComputed()){
658
//                        continue;
659
//                    }
660
//                    FeatureAttributeDescriptor csvAttr = featureType.getAttributeDescriptor(dalAttr.getName());
661
//                    if(csvAttr == null){
662
//                        return true;
663
//                    }
664
//                    if(!dalAttr.get("all").equals(csvAttr.get("all"))){
665
//                        return true;
666
//                    }
667
//                }
668
//            }
669
//        } catch (DataException ex) {
670
//            LOGGER.warn("Can't check if should fix the feature type", ex);
671
//        }
672
        return false;
673
    }
674

    
675
    private void setFeatureType(FeatureType ftype) {
676
        try {
677
            List<FeatureType> ftypes = new ArrayList<>();
678
            ftypes.add(ftype);
679
            this.featureType = ftype;
680
            if(this.getStoreServices().getDefaultFeatureType() == null){
681
                this.getStoreServices().setFeatureTypes(ftypes, ftype);
682
                return;
683
            }
684
            if(mustFixFeatureType()){
685
                this.getStoreServices().setFeatureTypes(ftypes, ftype);
686
            }
687
        } catch (DataException ex) {
688
            LOGGER.warn("Cant set feature type", ex);
689
        }
690
    }
691

    
692
    @Override
693
    public FeatureSetProvider createSet(FeatureQuery query, FeatureType providerFeatureType, FeatureType featureType)
694
            throws DataException {
695
        this.open();
696
        if (this.virtualrows == null) {
697
            return super.createSet(query, providerFeatureType, featureType);
698
        }
699
        return new SimpleReaderSetProvider(this, query, providerFeatureType, featureType);
700
    }
701

    
702
    @Override
703
    public FeatureSetProvider createSet(FeatureQuery query, FeatureType featureType)
704
            throws DataException {
705
        this.open();
706
        if (this.virtualrows == null) {
707
            return super.createSet(query, featureType);
708
        }
709
        return new SimpleReaderSetProvider(this, query, featureType, featureType);
710
    }
711

    
712
    public List<String> getRowByIndex(long index) {
713
        try {
714
            this.open();
715
        } catch(Exception ex) {
716
            throw new RuntimeException("Can't get row by index", ex);
717
        }
718
        if (this.virtualrows == null) {
719
            return null;
720
        }
721
        List<String> line = this.virtualrows.get64(index);
722
        return line;
723
    }
724

    
725
    public RowToFeatureTranslator getRowToFeatureTranslator() {
726
        if (this.rowToFeatureTranslator == null) {
727
            boolean ignore_errors = SimpleReaderStoreParameters.getIgnoreErrors(getSimpleReaderParameters());
728
            this.rowToFeatureTranslator = new RowToFeatureTranslator(ignore_errors);
729
            this.rowToFeatureTranslator.initialize(featureType);
730
        }
731
        return this.rowToFeatureTranslator;
732
    }
733

    
734
    @Override
735
    public long getFeatureCount() throws DataException {
736
        this.open();
737
        if (this.virtualrows == null) {
738
            return super.getFeatureCount();
739
        }
740
        return this.virtualrows.size64();
741
    }
742

    
743
    @Override
744
    public long getDataSize() throws DataException {
745
        this.open();
746
        if (this.virtualrows == null) {
747
            return super.getDataSize();
748
        }
749
        return this.virtualrows.size64();
750
    }
751

    
752
    @Override
753
    protected FeatureProvider internalGetFeatureProviderByReference(
754
            FeatureReferenceProviderServices reference) throws DataException {
755
        this.open();
756
        if (this.virtualrows == null) {
757
            return super.internalGetFeatureProviderByReference(reference);
758
        }
759
        int oid = ((Long) reference.getOID()).intValue();
760
        RowToFeatureTranslator translator = getRowToFeatureTranslator();
761
        FeatureProvider feature = this.createFeatureProvider(this.featureType);
762
        try {
763
            translator.translate(oid, this.virtualrows.get64(oid), feature);
764
        } catch (Exception ex) {
765
            throw new CreateFeatureException(ex, this.getName());
766
        }
767
        return feature;
768
    }
769

    
770
    @Override
771
    protected void doDispose() throws BaseException {
772
        super.doDispose();
773
        if (this.virtualrows != null && this.virtualrows instanceof Closeable) {
774
            IOUtils.closeQuietly((Closeable) this.virtualrows);
775
            this.virtualrows = null;
776
        }
777
    }
778
    
779
    @Override
780
     public void refresh() throws OpenException {
781
        try {
782
            this.close();
783
        } catch (CloseException e) {
784
            throw new OpenException(this.getProviderName(), e);
785
        }
786
        this.open();
787
    }
788

    
789
    @Override
790
    public void close() throws CloseException {
791
        super.close(); //To change body of generated methods, choose Tools | Templates.
792
        this.data = null;
793
        if(this.virtualrows != null && this.virtualrows instanceof Closeable){
794
            IOUtils.closeQuietly((Closeable) this.virtualrows);
795
            this.virtualrows = null;
796
            this.envelope = null;
797
            this.spatialIndex = null;
798
        }
799
        
800
    }
801
     
802
    
803
    private void loadOrCreateSpatialIndex() {
804
        FeatureSetProvider set = null;
805
        DisposableIterator<FeatureProvider> it = null;
806
        try {
807
            if( this.virtualrows == null ) {
808
                return;
809
            }
810
            FeatureAttributeDescriptor geomdesc = this.featureType.getDefaultGeometryAttribute();
811
            if( geomdesc == null ) {
812
                return;
813
            }
814
//            String indexTypeName = "MVRTree";
815
//            String extname = "mvtree";
816
            String indexTypeName = GeometryManager.SPATIALINDEX_DEFAULT_QUADTREE;
817
            String extname = "qtree";
818
            
819
            this.envelope = bboxFileLoad();
820
            File indexfile = this.getAuxFile(extname); 
821
            boolean createIndex = !indexfile.exists();
822

    
823
            GeometryManager geomManager = GeometryLocator.getGeometryManager();
824
            SpatialIndexFactory indexfactory = geomManager.getSpatialIndexFactory(indexTypeName);
825
            DynObject params = indexfactory.createParameters();
826
            params.setDynValue("file", indexfile);
827
            SpatialIndex index = geomManager.createSpatialIndex(indexTypeName, params);
828
            if( createIndex ) { 
829
                I18nManager i18n = ToolsLocator.getI18nManager();
830
                this.taskStatus.add();
831
                taskStatus.message(i18n.getTranslation("_Creating_spatial_index"));
832
                taskStatus.setRangeOfValues(0, this.virtualrows.size64());
833
                taskStatus.setCurValue(0);
834
                Envelope theEnvelope = geomManager.createEnvelope(Geometry.SUBTYPES.GEOM2D);
835
                set = this.createSet(null, featureType);
836
                it = set.fastIterator();
837
                while( it.hasNext() ) {
838
                    taskStatus.incrementCurrentValue();
839
                    if( taskStatus.isCancellationRequested() ) {
840
                        taskStatus.cancel();
841
                        LOGGER.info("CSV spatial index creation canceled ("+getFullFileName()+")");
842
                        break;
843
                    }
844
                    FeatureProvider f = it.next();
845
                    if( f == null ) {
846
                        continue;
847
                    }
848
                    Object oid = null;
849
                    try {
850
                        oid = f.getOID();
851
                        Geometry geom = (Geometry) f.get(geomdesc.getName());
852
                        index.insert(geom, oid);
853
                        theEnvelope.add(geom);
854
                    } catch(Exception ex) {
855
                        LOGGER.debug("Can't insert feature '"+Objects.toString(oid)+"' in spatial index.",ex);
856
                    }
857
                }
858
                taskStatus.message(i18n.getTranslation("_Saving_spatial_index"));
859
                taskStatus.setIndeterminate();
860
                index.flush();
861
                bboxFileSave(theEnvelope);
862
                taskStatus.terminate();
863
                this.envelope = theEnvelope;
864
            }
865
            this.spatialIndex = index;
866
        } catch (Exception ex) {
867
            taskStatus.abort();
868
            LOGGER.warn("Can't create spatial index.",ex);
869
        } finally {
870
            DisposeUtils.disposeQuietly(it);
871
            DisposeUtils.disposeQuietly(set);
872
            taskStatus.remove();
873
        }
874
    }
875

    
876
    public File getAuxFile(String extension) {
877
        File data_file = SimpleReaderStoreParameters.getFile(this.getSimpleReaderParameters());
878
        if (data_file == null){
879
            return null;
880
        }
881
        File index_file = new File(FilenameUtils.removeExtension(data_file.getAbsolutePath()) + "." + extension);
882
        return index_file;
883
    }
884

    
885
    public SpatialIndex getSpatialIndex() {
886
        return spatialIndex;
887
    }
888

    
889
    protected void bboxFileSave(Envelope envelope) {
890
        File bboxfile = this.getAuxFile("bbox");
891
        bboxFileSave(bboxfile, envelope);
892
    }
893
    
894
    protected void bboxFileSave(File bboxfile, Envelope envelope) {
895
        if( envelope == null ) {
896
            bboxfile.delete();
897
            return;
898
        }
899
        try {
900
            FileUtils.write(
901
                    bboxfile, 
902
                    envelope.getBox2D().convertToWKTQuietly(), 
903
                    StandardCharsets.UTF_8
904
            );
905
        } catch(Exception ex) {
906
            LOGGER.warn("Can't write bbox file '"+Objects.toString(bboxfile)+"'.",ex);
907
        }
908
    }
909
    
910
    protected Envelope bboxFileLoad() {
911
        File bboxfile = this.getAuxFile("bbox");
912
        return bboxFileLoad(bboxfile);
913
    }
914
    
915
    protected Envelope bboxFileLoad(File bboxfile) {
916
        try {
917
            if( bboxfile.exists() ) {
918
                GeometryManager geomManager = GeometryLocator.getGeometryManager();
919
                String wkt = FileUtils.readFileToString(bboxfile, StandardCharsets.UTF_8);                    
920
                Geometry geom = geomManager.createFrom(wkt);
921
                if( geom!=null ) {
922
                    return geom.getEnvelope();
923
                }
924
            }
925
        } catch(Exception ex) {
926
            LOGGER.warn("Can't load bbox file",ex);
927
        }
928
        return null;
929
    }
930
    
931
    protected abstract SimpleReader getSimpleReader(SimpleReaderStoreParameters parameters, Reader in) throws IOException ;//{
932
//        return CSVUtils.getSimpleReader(getSimpleReaderParameters(), in);
933
//    }
934
    
935
}