Revision 47636 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/csv/CSVStoreProvider.java

View differences:

CSVStoreProvider.java
22 22
 */
23 23
package org.gvsig.fmap.dal.store.csv;
24 24

  
25
import java.io.Closeable;
26 25
import java.io.File;
27 26
import java.io.IOException;
28
import java.io.InputStreamReader;
29
import java.net.URI;
30
import java.net.URL;
31
import java.nio.charset.StandardCharsets;
27
import java.io.Reader;
32 28
import java.util.ArrayList;
33
import java.util.HashMap;
34 29
import java.util.Iterator;
35 30
import java.util.List;
36
import java.util.Objects;
37 31
import org.apache.commons.io.FileUtils;
38

  
39 32
import org.apache.commons.io.FilenameUtils;
40
import org.apache.commons.io.IOUtils;
41
import org.apache.commons.lang3.StringUtils;
42
import org.cresques.cts.IProjection;
43
import org.gvsig.fmap.dal.DALLocator;
44
import org.gvsig.fmap.dal.DataManager;
45
import org.gvsig.fmap.dal.DataServerExplorer;
46 33
import org.gvsig.fmap.dal.DataStore;
47
import org.gvsig.fmap.dal.DataStoreNotification;
48
import org.gvsig.fmap.dal.DataTypes;
49 34
import org.gvsig.fmap.dal.FileHelper;
50
import org.gvsig.fmap.dal.exception.CloseException;
51 35
import org.gvsig.fmap.dal.exception.DataException;
52 36
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 37
import org.gvsig.fmap.dal.feature.FeatureSet;
61
import org.gvsig.fmap.dal.feature.FeatureStore;
62 38
import org.gvsig.fmap.dal.feature.FeatureType;
63
import org.gvsig.fmap.dal.feature.exception.CreateFeatureException;
64 39
import org.gvsig.fmap.dal.feature.exception.PerformEditingException;
65 40
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
66
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
67
import org.gvsig.fmap.dal.feature.spi.FeatureSetProvider;
68
import org.gvsig.fmap.dal.feature.spi.memory.AbstractMemoryStoreProvider;
69 41
import org.gvsig.fmap.dal.resource.ResourceAction;
70
import org.gvsig.fmap.dal.resource.file.FileResource;
71 42
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
72
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
73
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorer;
74
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorerParameters;
75 43
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
76
import org.gvsig.fmap.dal.store.csv.simplereaders.AbstractSimpleReader;
77 44
import org.gvsig.fmap.dal.store.csv.simplereaders.CSVReaderSuperCSV;
78
import org.gvsig.fmap.dal.store.csv.simplereaders.SimpleReader;
79
import org.gvsig.fmap.geom.Geometry;
80
import org.gvsig.fmap.geom.GeometryLocator;
81
import org.gvsig.fmap.geom.GeometryManager;
82
import org.gvsig.fmap.geom.SpatialIndex;
83
import org.gvsig.fmap.geom.SpatialIndexFactory;
84
import org.gvsig.fmap.geom.primitive.Envelope;
85
import org.gvsig.fmap.geom.primitive.Point;
45
import org.gvsig.fmap.dal.store.csv.simplereaders.FixedLenReader;
46
import org.gvsig.fmap.dal.store.simplereader.SimpleReader;
47
import org.gvsig.fmap.dal.store.simplereader.SimpleReaderFeatureTypeLoader;
48
import org.gvsig.fmap.dal.store.simplereader.SimpleReaderStoreParameters;
49
import org.gvsig.fmap.dal.store.simplereader.SimpleReaderStoreProvider;
86 50
import org.gvsig.tools.ToolsLocator;
87
import org.gvsig.tools.dataTypes.Coercion;
88 51
import org.gvsig.tools.dispose.DisposableIterator;
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.persistence.PersistentState;
96
import org.gvsig.tools.persistence.exception.PersistenceException;
97
import org.gvsig.tools.task.SimpleTaskStatus;
98
import org.gvsig.tools.task.TaskStatusManager;
99
import org.gvsig.tools.visitor.VisitCanceledException;
100
import org.gvsig.tools.visitor.Visitor;
52
import org.gvsig.tools.i18n.I18nManager;
101 53
import org.slf4j.Logger;
102 54
import org.slf4j.LoggerFactory;
103 55
import org.supercsv.prefs.CsvPreference;
104
import org.gvsig.tools.dataTypes.CoercionContext;
105
import org.gvsig.tools.dispose.DisposeUtils;
106
import org.gvsig.tools.dynobject.DynObject;
107
import org.gvsig.tools.i18n.I18nManager;
108
import org.gvsig.tools.util.GetItemWithSize64;
109 56

  
110 57
@SuppressWarnings("UseSpecificCatch")
111
public class CSVStoreProvider extends AbstractMemoryStoreProvider implements
58
public class CSVStoreProvider extends SimpleReaderStoreProvider implements
112 59
        ResourceConsumer {
113 60

  
114 61
    private static final Logger LOGGER = LoggerFactory.getLogger(CSVStoreProvider.class);
......
118 65

  
119 66
    public static final String METADATA_DEFINITION_NAME = NAME;
120 67

  
121
    private final ResourceProvider resource;
68
    protected final CSVFeatureWriter writer;
122 69

  
123
    private long counterNewsOIDs = 0;
124
    private Envelope envelope;
125
    private boolean need_calculate_envelope = false;
126
    private final SimpleTaskStatus taskStatus;
127
    private final CSVFeatureWriter writer;
128
    private FeatureType featureType;
129
    private GetItemWithSize64<List<String>> virtualrows;
130
    private RowToFeatureTranslator rowToFeatureTranslator;
131
    private SpatialIndex spatialIndex;
132
    
133 70
    @SuppressWarnings({"OverridableMethodCallInConstructor", "LeakingThisInConstructor"})
134 71
    public CSVStoreProvider(
135 72
            CSVStoreParameters parameters,
......
141 78
                FileHelper.newMetadataContainer(METADATA_DEFINITION_NAME)
142 79
        );
143 80
        this.writer = new CSVFeatureWriter();
144
        TaskStatusManager manager = ToolsLocator.getTaskStatusManager();
145
        this.taskStatus = manager.createDefaultSimpleTaskStatus("CSV");
146
        this.taskStatus.setAutoremove(true);
147

  
148
        counterNewsOIDs = 0;
149

  
150
        File file = getCSVParameters().getFile();
151
        resource = this.createResource(
152
                FileResource.NAME,
153
                new Object[]{file.getAbsolutePath()}
154
        );
155

  
156
        resource.addConsumer(this);
157

  
158
        initializeFeatureTypes();
159 81
    }
160 82

  
161 83
    private CSVStoreParameters getCSVParameters() {
......
172 94
        return true;
173 95
    }
174 96

  
175
    private String getFullFileName() {
176
        // Usar solo para mostrar mensajes en el logger.
177
        String s;
178
        try {
179
            s = getCSVParameters().getFile().getAbsolutePath();
180
        } catch (Exception e2) {
181
            s = "(unknow)";
182
        }
183
        return s;
184
    }
185

  
186 97
    @Override
187
    public void open() throws OpenException {
188
        if (this.data != null) {
189
            return;
190
        }
191
        this.data = new ArrayList<>();
192
        resource.setData(new HashMap());
193
        counterNewsOIDs = 0;
194
        try {
195
            loadFeatures();
196
        } catch (RuntimeException e) {
197
            LOGGER.debug("Can't load features from CSV '" + getFullFileName() + "'.", e);
198
            throw e;
199
        } catch (Exception e) {
200
            LOGGER.debug("Can't load features from CSV '" + getFullFileName() + "'.", e);
201
            throw new RuntimeException(e);
202
        }
203
    }
204

  
205
    @Override
206
    public DataServerExplorer getExplorer() throws ReadException {
207
        DataManager manager = DALLocator.getDataManager();
208
        FilesystemServerExplorerParameters params;
209
        try {
210
            params = (FilesystemServerExplorerParameters) manager
211
                    .createServerExplorerParameters(FilesystemServerExplorer.NAME);
212
            params.setRoot(this.getCSVParameters().getFile().getParent());
213
            return manager.openServerExplorer(FilesystemServerExplorer.NAME, params);
214
        } catch (Exception e) {
215
            throw new ReadException(this.getProviderName(), e);
216
        }
217

  
218
    }
219

  
220
    @Override
221 98
    @SuppressWarnings("Convert2Lambda")
222 99
    public void performChanges(Iterator deleteds, Iterator inserteds, Iterator updateds, Iterator originalFeatureTypesUpdated) throws PerformEditingException {
223 100

  
......
344 221
    }
345 222

  
346 223
    @Override
347
    public boolean closeResourceRequested(ResourceProvider resource) {
348
        return true;
349
    }
350

  
351
    @Override
352
    public int getOIDType() {
353
        return DataTypes.LONG;
354
    }
355

  
356
    @Override
357 224
    public boolean supportsAppendMode() {
358 225
        return true;
359 226
    }
......
418 285
        }
419 286
    }
420 287

  
421
    public void saveToState(PersistentState state) throws PersistenceException {
422
        throw new NotYetImplemented();
423
    }
424

  
425
    public void loadFromState(PersistentState state) throws PersistenceException {
426
        throw new NotYetImplemented();
427
    }
428

  
429
    @Override
430
    public Object createNewOID() {
431
        return counterNewsOIDs++;
432
    }
433

  
434
    protected void initializeFeatureTypes() throws InitializeException {
435
        try {
436
            this.open();
437
        } catch (OpenException e) {
438
            throw new InitializeException(this.getProviderName(), e);
439
        }
440
    }
441

  
442
    @Override
443
    @SuppressWarnings("Convert2Lambda")
444
    public Envelope getEnvelope() throws DataException {
445
        this.open();
446
        if (this.envelope != null) {
447
            return this.envelope;
448
        }
449
        this.envelope = bboxFileLoad();
450
        if (this.envelope != null) {
451
            return this.envelope;
452
        }
453
        if (!this.need_calculate_envelope) {
454
            return null;
455
        }
456
        try {
457
            I18nManager i18n = ToolsLocator.getI18nManager();
458
            this.taskStatus.add();
459
            this.taskStatus.message(i18n.getTranslation("_Calculating_envelope"));
460
            FeatureStore fs = this.getFeatureStore();
461
            FeatureType ft = fs.getDefaultFeatureType();
462
            FeatureAttributeDescriptor fad = ft.getAttributeDescriptor(ft.getDefaultGeometryAttributeIndex());
463
            this.taskStatus.setRangeOfValues(0, fs.getFeatureCount());
464
            this.envelope = GeometryLocator.getGeometryManager().createEnvelope(fad.getGeomType().getSubType());
465
            fs.accept(new Visitor() {
466
                @Override
467
                public void visit(Object obj) throws VisitCanceledException, BaseException {
468
                    taskStatus.incrementCurrentValue();
469
                    if(taskStatus.isCancellationRequested()){
470
                        taskStatus.cancel();
471
                        throw new VisitCanceledException();
472
                    }
473
                    Feature f = (Feature) obj;
474
                    Geometry geom = f.getDefaultGeometry();
475
                    if (geom != null) {
476
                        try {
477
                            Envelope env = geom.getEnvelope();
478
                            envelope.add(env);
479
                        } catch(Exception ex) {
480
                            LOGGER.warn("Can't calculate envelop of geometry in feature '"+Objects.toString(f.getReference())+"'.",ex);
481
                        }
482
                    }
483
                }
484
            });
485
            bboxFileSave(envelope);
486
            taskStatus.terminate();
487
        } catch (VisitCanceledException e) {
488
            return null;
489
        } catch (BaseException e) {
490
            taskStatus.abort();
491
            LOGGER.warn("Can't calculate the envelope of CSV file '" + this.getFullName() + "'.", e);
492
            return null;
493
        }
494

  
495
        this.need_calculate_envelope = false;
496
        return this.envelope;
497
    }
498

  
499
    @Override
500
    public Object getDynValue(String name) throws DynFieldNotFoundException {
501
        if (DataStore.METADATA_ENVELOPE.equalsIgnoreCase(name)) {
502
            try {
503
                return this.getEnvelope();
504
            } catch (DataException e) {
505
                return null;
506
            }
288
    protected SimpleReader getSimpleReader(SimpleReaderStoreParameters parameters, Reader in) throws IOException {
289
        SimpleReader reader;
290
        if (CSVStoreParameters.getRawFieldsDefinition(parameters) != null) {
291
            reader = new FixedLenReader(in, (CSVStoreParameters) parameters);
507 292
        } else {
508
            if (DataStore.METADATA_CRS.equalsIgnoreCase(name)) {
509
                IProjection pro = CSVStoreParameters.getCRS(this.getCSVParameters());
510
                if (pro != null) {
511
                    return pro;
512
                }
513
            }
293
            reader = new CSVReaderSuperCSV(in, (CSVStoreParameters) parameters);
514 294
        }
515
        return super.getDynValue(name);
295
        return reader;
516 296
    }
517 297

  
518 298
    @Override
519
    public void resourceChanged(ResourceProvider resource) {
520
        this.getStoreServices().notifyChange(
521
                DataStoreNotification.RESOURCE_CHANGED,
522
                resource);
299
    protected SimpleReaderFeatureTypeLoader getFeatureTypeLoader() {
300
        return new CSVFeatureTypeLoader(getCSVParameters());
523 301
    }
524 302

  
525
    @Override
526
    public Object getSourceId() {
527
        return this.getCSVParameters().getFile();
528
    }
529

  
530
    @Override
531
    public String getName() {
532
        String name = this.getCSVParameters().getFile().getName();
533
        return FilenameUtils.getBaseName(name);
534
    }
535

  
536
    @Override
537
    public String getFullName() {
538
        return this.getCSVParameters().getFile().getAbsolutePath();
539
    }
540

  
541
    @Override
542
    public ResourceProvider getResource() {
543
        return resource;
544
    }
545

  
546
    private boolean isEmpty(String s) {
547
        if (s == null) {
548
            return true;
549
        }
550
        return s.trim().length() == 0;
551
    }
552

  
553
    private void init(CSVStoreParameters parameters, DataStoreProviderServices storeServices) {
554
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
555
    }
556

  
557
    static class ToPointEvaluaror extends AbstractEvaluator {
558

  
559
        private static final Logger logger = LoggerFactory.getLogger(ToPointEvaluaror.class);
560

  
561
        private GeometryManager geommgr = null;
562
        private String xname = null;
563
        private String yname = null;
564
        private String zname = null;
565
        private final Coercion toDouble;
566
        private int errorcount = 0;
567

  
568
        ToPointEvaluaror(String[] pointDimensionNames) {
569
            this.xname = pointDimensionNames[0];
570
            this.yname = pointDimensionNames[1];
571
            if (pointDimensionNames.length > 2) {
572
                this.zname = pointDimensionNames[2];
573
            }
574
            this.geommgr = GeometryLocator.getGeometryManager();
575
            this.toDouble = ToolsLocator.getDataTypesManager().getCoercion(DataTypes.DOUBLE);
576
        }
577

  
578
        @Override
579
        public Object evaluate(EvaluatorData data) throws EvaluatorException {
580
            try {
581
                double x = ((Double) toDouble.coerce(data.getDataValue(xname)));
582
                double y = ((Double) toDouble.coerce(data.getDataValue(yname)));
583
                Point point = geommgr.createPoint(x, y, Geometry.SUBTYPES.GEOM3D);
584
                if (zname != null) {
585
                    double z = ((Double) toDouble.coerce(data.getDataValue(zname)));
586
                    point.setCoordinateAt(2, z);
587
                }
588
                return point;
589
            } catch (Exception ex) {
590
                if (++errorcount < 5) {
591
                    logger.warn("[" + errorcount + "] Can't create point in CSV provider. XNAME='"
592
                            + xname + "', YNAME='" + yname + "', ZNAME='" + zname + "', data=" + data.toString());
593
                }
594
                return null;
595
            }
596
        }
597

  
598
        @Override
599
        public String getName() {
600
            return "ToPointEvaluaror";
601
        }
602

  
603
    }
604

  
605
    public static class RowToFeatureTranslator {
606

  
607
        private Coercion coercion[];
608
        private CoercionContext coercionContext[];
609
        private int sizes[];
610
        private String[] names;
611
        private final boolean ignore_errors;
612
        private long count_errors;
613
        private FeatureType csvFeatureType;
614

  
615
        public RowToFeatureTranslator(boolean ignore_errors) {
616
            this.ignore_errors = ignore_errors;
617
            this.count_errors = 0;
618
        }
619

  
620
        public int getColumnSize(int column) {
621
            return this.sizes[column];
622
        }
623

  
624
        public void initialize(FeatureType ftype) {
625
            this.csvFeatureType = ftype;
626
            int columns = this.csvFeatureType.size();
627
            this.names = new String[columns];
628
            this.coercion = new Coercion[columns];
629
            this.coercionContext = new CoercionContext[columns];
630
            this.sizes = new int[columns];
631
            int index = 0;
632
            for (int i = 0; i < this.csvFeatureType.size(); i++) {
633
                FeatureAttributeDescriptor ad = this.csvFeatureType.getAttributeDescriptor(i);
634
                names[i] = null;
635
                if( ad.isComputed() ) {
636
                    continue;
637
                }
638
                names[index] = ad.getName();
639
                coercion[index] = ad.getCoercion();
640
                coercionContext[index] = ad.getCoercionContext();
641
                sizes[index] = ad.getSize();
642
                index++;
643
            }
644
        }
645

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

  
648
            feature.setOID(rowindex);
649
            for (int i = 0; i < names.length; i++) {
650
                String name = names[i];
651
                if( name == null ) {
652
                    break;
653
                }
654
                Object rawvalue = row.get(i);
655
                try {
656
                    Object value = null;
657
                    if (coercion[i] != null) {
658
                        value = coercion[i].coerce(rawvalue, coercionContext[i]);
659
                    }
660
                    int findex = feature.getType().getIndex(name);
661
                    if( findex>=0 ) {
662
                        // Ojo que puede que se este filtrando el featuretype y no 
663
                        // tenga todos los atributos, por ejemplo al pintar la vista.
664
                        feature.set(findex, value);
665
                    }
666
                    if (sizes[i] >= 0
667
                            && (value instanceof String || value instanceof URL
668
                            || value instanceof URI || value instanceof File)) {
669
                        int x = value.toString().length();
670
                        if (sizes[i] < x) {
671
                            sizes[i] = x;
672
                        }
673
                    }
674
                } catch (Exception ex) {
675
                    if (!ignore_errors) {
676
                        throw ex;
677
                    }
678
                    if (count_errors++ < 10) {
679
                        LOGGER.warn("Can't load value of attribute " + name +"/" +i+" in row " + rowindex + ".", ex);
680
                    }
681
                    if (count_errors == 10) {
682
                        LOGGER.info("Too many errors, suppress messages.");
683
                    }
684
                }
685
            }
686
        }
687
    }
688

  
689
    private void loadFeatures() {
690
        InputStreamReader in = null;
691
        SimpleReader reader = null;
692
        try {
693
            taskStatus.setTitle("CSV "+this.getName());
694
            taskStatus.add();
695
//            boolean ignore_errors = CSVStoreParameters.getIgnoreErrors(getCSVParameters());
696

  
697
            // Initialize the feature types
698
            EditableFeatureType edftype = getStoreServices().createFeatureType(this.getName());
699
            CSVUtils.loadFeatureType(getCSVParameters(), edftype, true, taskStatus);
700
            FeatureType ftype = edftype.getNotEditableCopy();
701
            this.setFeatureType(ftype);
702

  
703
            in = CSVUtils.openFile(
704
                    this.getCSVParameters().getFile(),
705
                    CSVStoreParameters.getCharset(this.getCSVParameters())
706
            );
707
            reader = CSVUtils.getSimpleReader(getCSVParameters(), in);
708
            if (CSVStoreParameters.isFirstLineHeader(getCSVParameters())) {
709
                reader.getHeader(); // Skip and ignore the header of file
710
            }
711
            this.rowToFeatureTranslator = new RowToFeatureTranslator(
712
                    CSVStoreParameters.getIgnoreErrors(getCSVParameters())
713
            );
714
            this.rowToFeatureTranslator.initialize(ftype);
715
            if (ftype.getDefaultGeometryAttributeName() != null) {
716
                this.need_calculate_envelope = true;
717
            }
718
            I18nManager i18n = ToolsLocator.getI18nManager();
719
            taskStatus.message(i18n.getTranslation("_Loading"));
720

  
721
            if(this.virtualrows != null && this.virtualrows instanceof Closeable){
722
                IOUtils.closeQuietly((Closeable) this.virtualrows);
723
                this.virtualrows = null;
724
            }
725
            
726
            this.virtualrows = ((AbstractSimpleReader) reader).getVirtualRows(this.taskStatus);
727
            if (this.virtualrows == null) {
728

  
729
                List<String> row = reader.read();
730

  
731
                int skipLines = CSVStoreParameters.getSkipLines(getCSVParameters());
732
                if (skipLines > 0) {
733
                    row = reader.skip(skipLines);
734
                }
735
                int limit = CSVStoreParameters.getLimit(getCSVParameters());
736
                while (row != null) {
737
                    taskStatus.incrementCurrentValue();
738
                    if( taskStatus.isCancellationRequested() ) {
739
                        taskStatus.cancel();
740
                        break;
741
                    }
742
                    FeatureProvider feature = this.createFeatureProvider(ftype);
743
                    this.rowToFeatureTranslator.translate(reader.getLine(), row, feature);
744

  
745
                    this.addFeatureProvider(feature);
746
                    if (limit > 0) {
747
                        if (limit < this.data.size()) {
748
                            break;
749
                        }
750
                    }
751
                    row = reader.read();
752
                }
753
                for (int i = 0; i < ftype.size(); i++) {
754
                    if (this.rowToFeatureTranslator.getColumnSize(i) > 0) {
755
//                    if (sizes[i] > 0) {
756
                        EditableFeatureAttributeDescriptor efad = ((EditableFeatureAttributeDescriptor) edftype.getAttributeDescriptor(i));
757
//                        efad.setSize(sizes[i]);
758
                        efad.setSize(this.rowToFeatureTranslator.getColumnSize(i));
759
                    }
760
                }
761
                // Volvemos a asignar al store el featuretype, ya que puede
762
                // haber cambiado.
763
                ftype = edftype.getNotEditableCopy();
764
                this.setFeatureType(ftype);
765
            } else {
766
                this.loadOrCreateSpatialIndex();
767
            }
768
            if( taskStatus.isRunning() ) {
769
                taskStatus.terminate();
770
            }
771
        } catch (Throwable ex) {
772
            taskStatus.abort();
773
            int lineno = 0;
774
            if (reader != null) {
775
                lineno = reader.getLine();
776
            }
777
            throw new RuntimeException("Problems reading file '" + getFullFileName() + "' near line " + lineno + ".", ex);
778

  
779
        } finally {
780
            if (reader != null) {
781
                try {
782
                    reader.close();
783
                } catch (Exception ex) {
784
                    // Do nothing
785
                }
786
//                reader = null;
787
            }
788
            if (in != null) {
789
                try {
790
                    in.close();
791
                } catch (Exception ex) {
792
                    // Do nothing
793
                }
794
//                in = null;
795
            }
796
            taskStatus.remove();
797
        }
798
    }
799

  
800
    @Override
801
    public void fixFeatureTypeFromParameters() {
802
        if(mustFixFeatureType() && featureType != null){
803
            this.setFeatureType(featureType);
804
        }
805
    }
806
    
807
    private boolean mustFixFeatureType() {
808
        try {
809
            String param_types_def = CSVStoreParameters.getRawFieldTypes(this.getParameters());
810
            String[] pointDimensionNames = CSVStoreParameters.getPointDimensionNames(this.getParameters());
811
            String geometry_column = CSVStoreParameters.getGeometryColumn(this.getParameters());
812
            
813
            
814
            FeatureType dalFeatureType = this.getStoreServices().getDefaultFeatureType();
815
            if (StringUtils.isNotBlank(geometry_column)){
816
                FeatureAttributeDescriptor attr = dalFeatureType.getAttributeDescriptor(geometry_column);
817
                if(attr == null || attr.getType() !=  DataTypes.GEOMETRY){
818
                    return true;
819
                }
820
            }
821
            if (StringUtils.isNotBlank(param_types_def)
822
                    || pointDimensionNames != null) {
823
                for (FeatureAttributeDescriptor dalAttr : dalFeatureType) {
824
                    if(dalAttr.isComputed()){
825
                        continue;
826
                    }
827
                    FeatureAttributeDescriptor csvAttr = featureType.getAttributeDescriptor(dalAttr.getName());
828
                    if(csvAttr == null){
829
                        return true;
830
                    }
831
                    if(!dalAttr.get("all").equals(csvAttr.get("all"))){
832
                        return true;
833
                    }
834
                }
835
            }
836
        } catch (DataException ex) {
837
            LOGGER.warn("Can't check if should fix the feature type", ex);
838
        }
839
        return false;
840
    }
841

  
842
    private void setFeatureType(FeatureType ftype) {
843
        try {
844
            List<FeatureType> ftypes = new ArrayList<>();
845
            ftypes.add(ftype);
846
            this.featureType = ftype;
847
            if(this.getStoreServices().getDefaultFeatureType() == null){
848
                this.getStoreServices().setFeatureTypes(ftypes, ftype);
849
                return;
850
            }
851
            if(mustFixFeatureType()){
852
                this.getStoreServices().setFeatureTypes(ftypes, ftype);
853
            }
854
        } catch (DataException ex) {
855
            LOGGER.warn("Cant set feature type", ex);
856
        }
857
    }
858

  
859
    @Override
860
    public FeatureSetProvider createSet(FeatureQuery query, FeatureType providerFeatureType, FeatureType featureType)
861
            throws DataException {
862
        this.open();
863
        if (this.virtualrows == null) {
864
            return super.createSet(query, providerFeatureType, featureType);
865
        }
866
        return new CSVSetProvider(this, query, providerFeatureType, featureType);
867
    }
868

  
869
    @Override
870
    public FeatureSetProvider createSet(FeatureQuery query, FeatureType featureType)
871
            throws DataException {
872
        this.open();
873
        if (this.virtualrows == null) {
874
            return super.createSet(query, featureType);
875
        }
876
        return new CSVSetProvider(this, query, featureType, featureType);
877
    }
878

  
879
    public List<String> getRowByIndex(long index) {
880
        try {
881
            this.open();
882
        } catch(Exception ex) {
883
            throw new RuntimeException("Can't get row by index", ex);
884
        }
885
        if (this.virtualrows == null) {
886
            return null;
887
        }
888
        List<String> line = this.virtualrows.get64(index);
889
        if( line!=null ) {
890
            for (int i = 0; i < line.size(); i++) {
891
                String s = line.get(i);
892
                line.set(i, CSVReaderSuperCSV.unescapeCRLF(s));
893
            }
894
        }      
895
        return line;
896
    }
897

  
898
    public RowToFeatureTranslator getRowToFeatureTranslator() {
899
        if (this.rowToFeatureTranslator == null) {
900
            boolean ignore_errors = CSVStoreParameters.getIgnoreErrors(getCSVParameters());
901
            this.rowToFeatureTranslator = new RowToFeatureTranslator(ignore_errors);
902
            this.rowToFeatureTranslator.initialize(featureType);
903
        }
904
        return this.rowToFeatureTranslator;
905
    }
906

  
907
    @Override
908
    public long getFeatureCount() throws DataException {
909
        this.open();
910
        if (this.virtualrows == null) {
911
            return super.getFeatureCount();
912
        }
913
        return this.virtualrows.size64();
914
    }
915

  
916
    @Override
917
    public long getDataSize() throws DataException {
918
        this.open();
919
        if (this.virtualrows == null) {
920
            return super.getDataSize();
921
        }
922
        return this.virtualrows.size64();
923
    }
924

  
925
    @Override
926
    protected FeatureProvider internalGetFeatureProviderByReference(
927
            FeatureReferenceProviderServices reference) throws DataException {
928
        this.open();
929
        if (this.virtualrows == null) {
930
            return super.internalGetFeatureProviderByReference(reference);
931
        }
932
        int oid = ((Long) reference.getOID()).intValue();
933
        RowToFeatureTranslator translator = getRowToFeatureTranslator();
934
        FeatureProvider feature = this.createFeatureProvider(this.featureType);
935
        try {
936
            translator.translate(oid, this.virtualrows.get64(oid), feature);
937
        } catch (Exception ex) {
938
            throw new CreateFeatureException(ex, this.getName());
939
        }
940
        return feature;
941
    }
942

  
943
    @Override
944
    protected void doDispose() throws BaseException {
945
        super.doDispose();
946
        if (this.virtualrows != null && this.virtualrows instanceof Closeable) {
947
            IOUtils.closeQuietly((Closeable) this.virtualrows);
948
            this.virtualrows = null;
949
        }
950
    }
951
    
952
    @Override
953
     public void refresh() throws OpenException {
954
        try {
955
            this.close();
956
        } catch (CloseException e) {
957
            throw new OpenException(this.getProviderName(), e);
958
        }
959
        this.open();
960
    }
961

  
962
    @Override
963
    public void close() throws CloseException {
964
        super.close(); //To change body of generated methods, choose Tools | Templates.
965
        this.data = null;
966
        if(this.virtualrows != null && this.virtualrows instanceof Closeable){
967
            IOUtils.closeQuietly((Closeable) this.virtualrows);
968
            this.virtualrows = null;
969
            this.envelope = null;
970
            this.spatialIndex = null;
971
        }
972
        
973
    }
974
     
975
    
976
    private void loadOrCreateSpatialIndex() {
977
        FeatureSetProvider set = null;
978
        DisposableIterator<FeatureProvider> it = null;
979
        try {
980
            if( this.virtualrows == null ) {
981
                return;
982
            }
983
            FeatureAttributeDescriptor geomdesc = this.featureType.getDefaultGeometryAttribute();
984
            if( geomdesc == null ) {
985
                return;
986
            }
987
//            String indexTypeName = "MVRTree";
988
//            String extname = "mvtree";
989
            String indexTypeName = GeometryManager.SPATIALINDEX_DEFAULT_QUADTREE;
990
            String extname = "qtree";
991
            
992
            this.envelope = bboxFileLoad();
993
            File indexfile = this.getAuxFile(extname); 
994
            boolean createIndex = !indexfile.exists();
995

  
996
            GeometryManager geomManager = GeometryLocator.getGeometryManager();
997
            SpatialIndexFactory indexfactory = geomManager.getSpatialIndexFactory(indexTypeName);
998
            DynObject params = indexfactory.createParameters();
999
            params.setDynValue("file", indexfile);
1000
            SpatialIndex index = geomManager.createSpatialIndex(indexTypeName, params);
1001
            if( createIndex ) { 
1002
                I18nManager i18n = ToolsLocator.getI18nManager();
1003
                this.taskStatus.add();
1004
                taskStatus.message(i18n.getTranslation("_Creating_spatial_index"));
1005
                taskStatus.setRangeOfValues(0, this.virtualrows.size64());
1006
                taskStatus.setCurValue(0);
1007
                Envelope theEnvelope = geomManager.createEnvelope(Geometry.SUBTYPES.GEOM2D);
1008
                set = this.createSet(null, featureType);
1009
                it = set.fastIterator();
1010
                while( it.hasNext() ) {
1011
                    taskStatus.incrementCurrentValue();
1012
                    if( taskStatus.isCancellationRequested() ) {
1013
                        taskStatus.cancel();
1014
                        LOGGER.info("CSV spatial index creation canceled ("+getFullFileName()+")");
1015
                        break;
1016
                    }
1017
                    FeatureProvider f = it.next();
1018
                    if( f == null ) {
1019
                        continue;
1020
                    }
1021
                    Object oid = null;
1022
                    try {
1023
                        oid = f.getOID();
1024
                        Geometry geom = (Geometry) f.get(geomdesc.getName());
1025
                        index.insert(geom, oid);
1026
                        theEnvelope.add(geom);
1027
                    } catch(Exception ex) {
1028
                        LOGGER.debug("Can't insert feature '"+Objects.toString(oid)+"' in spatial index.",ex);
1029
                    }
1030
                }
1031
                taskStatus.message(i18n.getTranslation("_Saving_spatial_index"));
1032
                taskStatus.setIndeterminate();
1033
                index.flush();
1034
                bboxFileSave(theEnvelope);
1035
                taskStatus.terminate();
1036
                this.envelope = theEnvelope;
1037
            }
1038
            this.spatialIndex = index;
1039
        } catch (Exception ex) {
1040
            taskStatus.abort();
1041
            LOGGER.warn("Can't create spatial index.",ex);
1042
        } finally {
1043
            DisposeUtils.disposeQuietly(it);
1044
            DisposeUtils.disposeQuietly(set);
1045
            taskStatus.remove();
1046
        }
1047
    }
1048

  
1049
    public File getAuxFile(String extension) {
1050
        File data_file = CSVStoreParameters.getFile(this.getCSVParameters());
1051
        if (data_file == null){
1052
            return null;
1053
        }
1054
        File index_file = new File(FilenameUtils.removeExtension(data_file.getAbsolutePath()) + "." + extension);
1055
        return index_file;
1056
    }
1057

  
1058
    public SpatialIndex getSpatialIndex() {
1059
        return spatialIndex;
1060
    }
1061

  
1062
    private void bboxFileSave(Envelope envelope) {
1063
        File bboxfile = this.getAuxFile("bbox");
1064
        bboxFileSave(bboxfile, envelope);
1065
    }
1066
    
1067
    private void bboxFileSave(File bboxfile, Envelope envelope) {
1068
        if( envelope == null ) {
1069
            bboxfile.delete();
1070
            return;
1071
        }
1072
        try {
1073
            FileUtils.write(
1074
                    bboxfile, 
1075
                    envelope.getBox2D().convertToWKTQuietly(), 
1076
                    StandardCharsets.UTF_8
1077
            );
1078
        } catch(Exception ex) {
1079
            LOGGER.warn("Can't write bbox file '"+Objects.toString(bboxfile)+"'.",ex);
1080
        }
1081
    }
1082
    
1083
    private Envelope bboxFileLoad() {
1084
        File bboxfile = this.getAuxFile("bbox");
1085
        return bboxFileLoad(bboxfile);
1086
    }
1087
    
1088
    private Envelope bboxFileLoad(File bboxfile) {
1089
        try {
1090
            if( bboxfile.exists() ) {
1091
                GeometryManager geomManager = GeometryLocator.getGeometryManager();
1092
                String wkt = FileUtils.readFileToString(bboxfile, StandardCharsets.UTF_8);                    
1093
                Geometry geom = geomManager.createFrom(wkt);
1094
                if( geom!=null ) {
1095
                    return geom.getEnvelope();
1096
                }
1097
            }
1098
        } catch(Exception ex) {
1099
            LOGGER.warn("Can't load bbox file",ex);
1100
        }
1101
        return null;
1102
    }
1103
    
1104 303
}

Also available in: Unified diff