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

History | View | Annotate | Download (36.3 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.Map;
38
import java.util.Objects;
39
import org.apache.commons.io.FileUtils;
40
import org.apache.commons.io.FilenameUtils;
41
import org.apache.commons.io.IOUtils;
42
import org.apache.commons.lang3.StringUtils;
43
import org.cresques.cts.IProjection;
44
import org.gvsig.fmap.dal.DALLocator;
45
import org.gvsig.fmap.dal.DataManager;
46
import org.gvsig.fmap.dal.DataServerExplorer;
47
import org.gvsig.fmap.dal.DataStore;
48
import org.gvsig.fmap.dal.DataStoreNotification;
49
import org.gvsig.fmap.dal.DataTypes;
50
import org.gvsig.fmap.dal.exception.CloseException;
51
import org.gvsig.fmap.dal.exception.DataException;
52
import org.gvsig.fmap.dal.exception.InitializeException;
53
import org.gvsig.fmap.dal.exception.OpenException;
54
import org.gvsig.fmap.dal.exception.ReadException;
55
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
56
import org.gvsig.fmap.dal.feature.EditableFeatureType;
57
import org.gvsig.fmap.dal.feature.Feature;
58
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
59
import org.gvsig.fmap.dal.feature.FeatureQuery;
60
import org.gvsig.fmap.dal.feature.FeatureStore;
61
import org.gvsig.fmap.dal.feature.FeatureType;
62
import org.gvsig.fmap.dal.feature.exception.CreateFeatureException;
63
import org.gvsig.fmap.dal.feature.exception.PerformEditingException;
64
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
65
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
66
import org.gvsig.fmap.dal.feature.spi.FeatureSetProvider;
67
import org.gvsig.fmap.dal.feature.spi.memory.AbstractMemoryStoreProvider;
68
import org.gvsig.fmap.dal.resource.file.FileResource;
69
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
70
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
71
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorer;
72
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorerParameters;
73
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
74
import org.gvsig.fmap.dal.store.simplereader.simplereaders.AbstractSimpleReader;
75
import org.gvsig.fmap.dal.store.simplereader.simplereaders.SimpleReader;
76
import org.gvsig.fmap.geom.Geometry;
77
import org.gvsig.fmap.geom.GeometryLocator;
78
import org.gvsig.fmap.geom.GeometryManager;
79
import org.gvsig.fmap.geom.SpatialIndex;
80
import org.gvsig.fmap.geom.SpatialIndexFactory;
81
import org.gvsig.fmap.geom.primitive.Envelope;
82
import org.gvsig.fmap.geom.primitive.Point;
83
import org.gvsig.tools.ToolsLocator;
84
import org.gvsig.tools.dataTypes.Coercion;
85
import org.gvsig.tools.dataTypes.CoercionContext;
86
import org.gvsig.tools.dispose.DisposableIterator;
87
import org.gvsig.tools.dispose.DisposeUtils;
88
import org.gvsig.tools.dynobject.DynObject;
89
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
90
import org.gvsig.tools.evaluator.AbstractEvaluator;
91
import org.gvsig.tools.evaluator.EvaluatorData;
92
import org.gvsig.tools.evaluator.EvaluatorException;
93
import org.gvsig.tools.exception.BaseException;
94
import org.gvsig.tools.exception.NotYetImplemented;
95
import org.gvsig.tools.i18n.I18nManager;
96
import org.gvsig.tools.persistence.PersistentState;
97
import org.gvsig.tools.persistence.exception.PersistenceException;
98
import org.gvsig.tools.task.SimpleTaskStatus;
99
import org.gvsig.tools.task.TaskStatusManager;
100
import org.gvsig.tools.task.UserCancelTaskException;
101
import org.gvsig.tools.util.GetItemWithSize64;
102
import org.gvsig.tools.visitor.VisitCanceledException;
103
import org.gvsig.tools.visitor.Visitor;
104
import org.slf4j.Logger;
105
import org.slf4j.LoggerFactory;
106

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

    
111
    protected static final Logger LOGGER = LoggerFactory.getLogger(SimpleReaderStoreProvider.class);
112

    
113
    protected final ResourceProvider resource;
114

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

    
139
        this.envelopes = new HashMap<>();
140
        counterNewsOIDs = 0;
141

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

    
148
        resource.addConsumer(this);
149

    
150
        initializeFeatureTypes();
151
    }
152

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

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

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

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

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

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

    
208
    }
209

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

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

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

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

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

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

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

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

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

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

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

    
270
    public Envelope getEnvelope(String geomName) throws DataException {
271
        this.open();
272
        if(geomName == null){
273
            FeatureAttributeDescriptor geomdesc = this.featureType.getDefaultGeometryAttribute();
274
            geomName = geomdesc.getName();
275
        }
276
        Envelope env = this.envelopes.get(geomName);
277
        if (env != null) {
278
            return env;
279
        }
280

    
281
        File data_file = SimpleReaderStoreParameters.getFile(this.getSimpleReaderParameters());
282
        File bboxfile = this.getAuxFile("_"+geomName, "bbox");
283
        if (bboxfile.exists() && SimpleReaderUtils.isFileNewer(bboxfile, data_file)) {
284
            env = bboxFileLoad(bboxfile);
285
            if (env != null) {
286
                this.envelopes.put(geomName, env);
287
                return env;
288
            }
289
        }
290
        if (!this.need_calculate_envelope) {
291
            return null;
292
        }
293
        try {
294
            I18nManager i18n = ToolsLocator.getI18nManager();
295
            this.taskStatus.add();
296
            this.taskStatus.message(i18n.getTranslation("_Calculating_envelope"));
297
            FeatureStore fs = this.getFeatureStore();
298
            FeatureType ft = fs.getDefaultFeatureType();
299
            FeatureAttributeDescriptor fad = ft.getAttributeDescriptor(ft.getDefaultGeometryAttributeIndex());
300
            this.taskStatus.setRangeOfValues(0, fs.getFeatureCount());
301
            env = GeometryLocator.getGeometryManager().createEnvelope(fad.getGeomType().getSubType());
302
            fs.accept(new Visitor() {
303
                @Override
304
                public void visit(Object obj) throws VisitCanceledException, BaseException {
305
                    taskStatus.incrementCurrentValue();
306
                    if(taskStatus.isCancellationRequested()){
307
                        taskStatus.cancel();
308
                        throw new VisitCanceledException();
309
                    }
310
                    Feature f = (Feature) obj;
311
                    Geometry geom = f.getDefaultGeometry();
312
                    if (geom != null) {
313
                        try {
314
                            Envelope env = geom.getEnvelope();
315
                            env.add(env);
316
                        } catch(Exception ex) {
317
                            LOGGER.warn("Can't calculate envelop of geometry in feature '"+Objects.toString(f.getReference())+"'.",ex);
318
                        }
319
                    }
320
                }
321
            });
322
            bboxFileSave("_"+geomName,env);
323
            taskStatus.terminate();
324
        } catch (VisitCanceledException e) {
325
            return null;
326
        } catch (BaseException e) {
327
            taskStatus.abort();
328
            LOGGER.warn("Can't calculate the envelope of file '" + this.getFullName() + "'.", e);
329
            return null;
330
        }
331

    
332
        this.need_calculate_envelope = false;
333
        return env;
334
        
335
    }
336
    
337
    @Override
338
    public Envelope getEnvelope() throws DataException {
339
        return getEnvelope(null);
340
    }
341

    
342
    @Override
343
    public Object getDynValue(String name) throws DynFieldNotFoundException {
344
        if (DataStore.METADATA_ENVELOPE.equalsIgnoreCase(name)) {
345
            try {
346
                return this.getEnvelope();
347
            } catch (DataException e) {
348
                return null;
349
            }
350
        } else {
351
            if (DataStore.METADATA_CRS.equalsIgnoreCase(name)) {
352
                IProjection pro = SimpleReaderStoreParameters.getCRS(this.getSimpleReaderParameters());
353
                if (pro != null) {
354
                    return pro;
355
                }
356
            }
357
        }
358
        return super.getDynValue(name);
359
    }
360

    
361
    @Override
362
    public void resourceChanged(ResourceProvider resource) {
363
        this.getStoreServices().notifyChange(
364
                DataStoreNotification.RESOURCE_CHANGED,
365
                resource);
366
    }
367

    
368
    @Override
369
    public Object getSourceId() {
370
        return this.getSimpleReaderParameters().getFile();
371
    }
372

    
373
    @Override
374
    public String getName() {
375
        String name = this.getSimpleReaderParameters().getFile().getName();
376
        return FilenameUtils.getBaseName(name);
377
    }
378

    
379
    @Override
380
    public String getFullName() {
381
        return this.getSimpleReaderParameters().getFile().getAbsolutePath();
382
    }
383

    
384
    @Override
385
    public ResourceProvider getResource() {
386
        return resource;
387
    }
388

    
389
    private boolean isEmpty(String s) {
390
        if (s == null) {
391
            return true;
392
        }
393
        return s.trim().length() == 0;
394
    }
395

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

    
400
    static class ToPointEvaluaror extends AbstractEvaluator {
401

    
402
        private static final Logger logger = LoggerFactory.getLogger(ToPointEvaluaror.class);
403

    
404
        private GeometryManager geommgr = null;
405
        private String xname = null;
406
        private String yname = null;
407
        private String zname = null;
408
        private final Coercion toDouble;
409
        private int errorcount = 0;
410

    
411
        ToPointEvaluaror(String[] pointDimensionNames) {
412
            this.xname = pointDimensionNames[0];
413
            this.yname = pointDimensionNames[1];
414
            if (pointDimensionNames.length > 2) {
415
                this.zname = pointDimensionNames[2];
416
            }
417
            this.geommgr = GeometryLocator.getGeometryManager();
418
            this.toDouble = ToolsLocator.getDataTypesManager().getCoercion(DataTypes.DOUBLE);
419
        }
420

    
421
        @Override
422
        public Object evaluate(EvaluatorData data) throws EvaluatorException {
423
            try {
424
                double x = ((Double) toDouble.coerce(data.getDataValue(xname)));
425
                double y = ((Double) toDouble.coerce(data.getDataValue(yname)));
426
                Point point = geommgr.createPoint(x, y, Geometry.SUBTYPES.GEOM3D);
427
                if (zname != null) {
428
                    double z = ((Double) toDouble.coerce(data.getDataValue(zname)));
429
                    point.setCoordinateAt(2, z);
430
                }
431
                return point;
432
            } catch (Exception ex) {
433
                if (++errorcount < 5) {
434
                    logger.warn("[" + errorcount + "] Can't create point. XNAME='"
435
                            + xname + "', YNAME='" + yname + "', ZNAME='" + zname + "', data=" + data.toString());
436
                }
437
                return null;
438
            }
439
        }
440

    
441
        @Override
442
        public String getName() {
443
            return "ToPointEvaluaror";
444
        }
445

    
446
    }
447

    
448
    public static class RowToFeatureTranslator {
449

    
450
        private Coercion coercion[];
451
        private CoercionContext coercionContext[];
452
        private int sizes[];
453
        private String[] names;
454
        private final boolean ignore_errors;
455
        private long count_errors;
456
        private FeatureType csvFeatureType;
457

    
458
        public RowToFeatureTranslator(boolean ignore_errors) {
459
            this.ignore_errors = ignore_errors;
460
            this.count_errors = 0;
461
        }
462

    
463
        public int getColumnSize(int column) {
464
            return this.sizes[column];
465
        }
466

    
467
        public void initialize(FeatureType ftype) {
468
            this.csvFeatureType = ftype;
469
            int columns = this.csvFeatureType.size();
470
            this.names = new String[columns];
471
            this.coercion = new Coercion[columns];
472
            this.coercionContext = new CoercionContext[columns];
473
            this.sizes = new int[columns];
474
            int index = 0;
475
            for (int i = 0; i < this.csvFeatureType.size(); i++) {
476
                FeatureAttributeDescriptor ad = this.csvFeatureType.getAttributeDescriptor(i);
477
                names[i] = null;
478
                if( ad.isComputed() ) {
479
                    continue;
480
                }
481
                names[index] = ad.getName();
482
                coercion[index] = ad.getCoercion();
483
                coercionContext[index] = ad.getCoercionContext();
484
                sizes[index] = ad.getSize();
485
                index++;
486
            }
487
        }
488

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

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

    
532
    protected abstract SimpleReaderFeatureTypeLoader getFeatureTypeLoader();
533
    
534
    protected void loadFeatures() {
535
        InputStreamReader in = null;
536
        SimpleReader reader = null;
537
        try {
538
            taskStatus.setTitle(this.getProviderName()+" "+this.getName());
539
            taskStatus.add();
540

    
541
            // Initialize the feature types
542
            EditableFeatureType edftype = getStoreServices().createFeatureType(this.getName());
543
            SimpleReaderFeatureTypeLoader featureTypeLoader = getFeatureTypeLoader();
544
            featureTypeLoader.loadFeatureType(edftype, taskStatus);
545
            FeatureType ftype = edftype.getNotEditableCopy();
546
            this.setFeatureType(ftype);
547

    
548
            in = SimpleReaderUtils.openFile(
549
                    this.getSimpleReaderParameters().getFile(),
550
                    SimpleReaderStoreParameters.getCharset(this.getSimpleReaderParameters())
551
            );
552
            reader = getSimpleReader(getSimpleReaderParameters(), in);
553
            if (featureTypeLoader.isFirstLineHeader()) {
554
                reader.getHeader(); // Skip and ignore the header of file
555
            }
556
            this.rowToFeatureTranslator = new RowToFeatureTranslator(
557
                    SimpleReaderStoreParameters.getIgnoreErrors(getSimpleReaderParameters())
558
            );
559
            this.rowToFeatureTranslator.initialize(ftype);
560
            if (ftype.getDefaultGeometryAttributeName() != null) {
561
                this.need_calculate_envelope = true;
562
            }
563
            I18nManager i18n = ToolsLocator.getI18nManager();
564
            taskStatus.message(i18n.getTranslation("_Loading"));
565

    
566
            if(this.virtualrows != null && this.virtualrows instanceof Closeable){
567
                IOUtils.closeQuietly((Closeable) this.virtualrows);
568
                this.virtualrows = null;
569
            }
570
            
571
            this.virtualrows = ((AbstractSimpleReader) reader).getVirtualRows(this.taskStatus);
572
            if(this.taskStatus.isCancellationRequested()){
573
                throw new UserCancelTaskException();
574
            }
575
            if (this.virtualrows == null) {
576

    
577
                taskStatus.message(i18n.getTranslation("_Loading"));
578
                taskStatus.setIndeterminate();
579

    
580
                List<String> row = reader.read();
581

    
582
                int skipLines = SimpleReaderStoreParameters.getSkipLines(getSimpleReaderParameters());
583
                if (skipLines > 0) {
584
                    row = reader.skip(skipLines);
585
                }
586
                int limit = SimpleReaderStoreParameters.getLimit(getSimpleReaderParameters());
587
                while (row != null) {
588
                    taskStatus.incrementCurrentValue();
589
                    if( taskStatus.isCancellationRequested() ) {
590
                        taskStatus.cancel();
591
                        break;
592
                    }
593
                    FeatureProvider feature = this.createFeatureProvider(ftype);
594
                    this.rowToFeatureTranslator.translate(reader.getLine(), row, feature);
595

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

    
631
        } finally {
632
            if (reader != null) {
633
                try {
634
                    reader.close();
635
                } catch (Exception ex) {
636
                    // Do nothing
637
                }
638
//                reader = null;
639
            }
640
            if (in != null) {
641
                try {
642
                    in.close();
643
                } catch (Exception ex) {
644
                    // Do nothing
645
                }
646
//                in = null;
647
            }
648
            taskStatus.remove();
649
        }
650
    }
651

    
652
    @Override
653
    public void fixFeatureTypeFromParameters() {
654
        if(mustFixFeatureType() && featureType != null){
655
            this.setFeatureType(featureType);
656
        }
657
    }
658
    
659
    protected boolean mustFixFeatureType() {
660
        FeatureStore theStore = this.getStoreServices().getFeatureStore();
661
        FeatureType ft = theStore.getDefaultFeatureTypeQuietly();
662
        String geomName = ft.getDefaultGeometryAttributeName();
663
        if(StringUtils.isNotBlank(geomName)){
664
            if(this.featureType.getAttributeDescriptor(geomName)==null){
665
                return true;
666
            }
667
        }
668
        return false;
669
    }
670

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

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

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

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

    
721
    public RowToFeatureTranslator getRowToFeatureTranslator() {
722
        if (this.rowToFeatureTranslator == null) {
723
            boolean ignore_errors = SimpleReaderStoreParameters.getIgnoreErrors(getSimpleReaderParameters());
724
            this.rowToFeatureTranslator = new RowToFeatureTranslator(ignore_errors);
725
            this.rowToFeatureTranslator.initialize(featureType);
726
        }
727
        return this.rowToFeatureTranslator;
728
    }
729

    
730
    @Override
731
    public long getFeatureCount() throws DataException {
732
        this.open();
733
        if (this.virtualrows == null) {
734
            return super.getFeatureCount();
735
        }
736
        return this.virtualrows.size64();
737
    }
738

    
739
    @Override
740
    public long getDataSize() throws DataException {
741
        this.open();
742
        if (this.virtualrows == null) {
743
            return super.getDataSize();
744
        }
745
        return this.virtualrows.size64();
746
    }
747

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

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

    
785
    @Override
786
    public void close() throws CloseException {
787
        super.close(); //To change body of generated methods, choose Tools | Templates.
788
        this.data = null;
789
        if(this.virtualrows != null && this.virtualrows instanceof Closeable){
790
            IOUtils.closeQuietly((Closeable) this.virtualrows);
791
            this.virtualrows = null;
792
            this.envelopes = null;
793
            this.spatialIndexes = null;
794
        }
795
        
796
    }
797
     
798
    
799
    private void loadOrCreateSpatialIndex() {
800
        FeatureSetProvider set = null;
801
        DisposableIterator<FeatureProvider> it = null;
802
        try {
803
            if (this.virtualrows == null) {
804
                return;
805
            }
806
            
807
            this.spatialIndexes = new HashMap<>();
808

    
809
            for (FeatureAttributeDescriptor geomdesc : this.featureType) {
810
                if (geomdesc.getType() != DataTypes.GEOMETRY) {
811
                    continue;
812
                }
813
                String indexTypeName = GeometryManager.SPATIALINDEX_DEFAULT_QUADTREE;
814
                String extname = "qtree";
815
                String geomName = geomdesc.getName();
816
                Envelope env = bboxFileLoad("_"+geomName);
817
                File indexfile = this.getAuxFile("_"+geomName, extname);
818

    
819
                File data_file = SimpleReaderStoreParameters.getFile(this.getSimpleReaderParameters());
820
                boolean createIndex = !indexfile.exists() || SimpleReaderUtils.isFileNewer(data_file, indexfile);
821

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

    
882
    public File getAuxFile(String extension) {
883
        return getAuxFile(null, extension);
884
    }
885
    
886
    public File getAuxFile(String suffix, String extension) {
887
        File data_file = SimpleReaderStoreParameters.getFile(this.getSimpleReaderParameters());
888
        if (data_file == null){
889
            return null;
890
        }
891
        File index_file;
892
        if(StringUtils.isBlank(suffix)){
893
            index_file = new File(FilenameUtils.removeExtension(data_file.getAbsolutePath()) + "." + extension);
894
        } else {
895
            index_file = new File(FilenameUtils.removeExtension(data_file.getAbsolutePath()) + suffix + "." + extension);
896
        }
897
        return index_file;
898
    }
899

    
900
    public SpatialIndex getSpatialIndex(String geomName) {
901
        if(spatialIndexes == null){
902
            return null;
903
        }
904
        return spatialIndexes.get(geomName);
905
    }
906

    
907
    public SpatialIndex getSpatialIndex() {
908
        if(spatialIndexes == null){
909
            return null;
910
        }
911
        FeatureAttributeDescriptor geomdesc = this.featureType.getDefaultGeometryAttribute();
912
        if(geomdesc == null){
913
            return null;
914
        }
915
        return spatialIndexes.get(geomdesc.getName());
916
    }
917

    
918
    protected void bboxFileSave(Map<String,Envelope> envelopes) {
919
        for (Map.Entry<String, Envelope> entry : envelopes.entrySet()) {
920
            String key = entry.getKey();
921
            Envelope val = entry.getValue();
922
            bboxFileSave("_"+key, val);
923
        }
924
    }
925
    
926
    protected void bboxFileSave(Envelope envelope) {
927
        bboxFileSave((String)null, envelope);
928
    }
929
    
930
    protected void bboxFileSave(String suffix, Envelope envelope) {
931
        File bboxfile = this.getAuxFile(suffix,"bbox");
932
        bboxFileSave(bboxfile, envelope);
933
    }
934
    
935
    protected void bboxFileSave(File bboxfile, Envelope envelope) {
936
        if( envelope == null ) {
937
            bboxfile.delete();
938
            return;
939
        }
940
        try {
941
            FileUtils.write(
942
                    bboxfile, 
943
                    envelope.getBox2D().convertToWKTQuietly(), 
944
                    StandardCharsets.UTF_8
945
            );
946
        } catch(Exception ex) {
947
            LOGGER.warn("Can't write bbox file '"+Objects.toString(bboxfile)+"'.",ex);
948
        }
949
    }
950
    
951
    protected Envelope bboxFileLoad(String suffix) {
952
        File bboxfile = this.getAuxFile(suffix, "bbox");
953
        return bboxFileLoad(bboxfile);
954
    }
955
    
956
    protected Envelope bboxFileLoad(File bboxfile) {
957
        try {
958
            if( bboxfile.exists() ) {
959
                GeometryManager geomManager = GeometryLocator.getGeometryManager();
960
                String wkt = FileUtils.readFileToString(bboxfile, StandardCharsets.UTF_8);                    
961
                Geometry geom = geomManager.createFrom(wkt);
962
                if( geom!=null ) {
963
                    return geom.getEnvelope();
964
                }
965
            }
966
        } catch(Exception ex) {
967
            LOGGER.warn("Can't load bbox file",ex);
968
        }
969
        return null;
970
    }
971
    
972
    protected abstract SimpleReader getSimpleReader(SimpleReaderStoreParameters parameters, Reader in) throws IOException ;
973
    
974
}