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 / csv / CSVStoreProvider.java @ 43510

History | View | Annotate | Download (52.4 KB)

1 40846 jjdelcerro
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6 42775 jjdelcerro
 * 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 40846 jjdelcerro
 *
11 42775 jjdelcerro
 * 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 40846 jjdelcerro
 *
16 42775 jjdelcerro
 * 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 40846 jjdelcerro
 *
20 42775 jjdelcerro
 * For any additional information, do not hesitate to contact us at info AT
21
 * gvsig.com, or visit our website www.gvsig.com.
22 40846 jjdelcerro
 */
23
package org.gvsig.fmap.dal.store.csv;
24
25
import java.io.File;
26 43283 jjdelcerro
import java.io.FileInputStream;
27
import java.io.FileNotFoundException;
28 40846 jjdelcerro
import java.io.FileReader;
29 41006 jjdelcerro
import java.io.FileWriter;
30 40846 jjdelcerro
import java.io.IOException;
31 43283 jjdelcerro
import java.io.InputStreamReader;
32 43425 jjdelcerro
import java.net.URI;
33 41062 jjdelcerro
import java.net.URL;
34 43283 jjdelcerro
import java.nio.charset.Charset;
35 40846 jjdelcerro
import java.util.ArrayList;
36
import java.util.HashMap;
37 41006 jjdelcerro
import java.util.Iterator;
38 40846 jjdelcerro
import java.util.List;
39 41069 jjdelcerro
import java.util.Locale;
40 40846 jjdelcerro
41 41006 jjdelcerro
import org.apache.commons.io.FilenameUtils;
42 42775 jjdelcerro
import org.apache.commons.io.IOUtils;
43 41876 jjdelcerro
import org.apache.commons.lang3.StringUtils;
44 40846 jjdelcerro
import org.cresques.cts.IProjection;
45
import org.gvsig.fmap.dal.DALLocator;
46
import org.gvsig.fmap.dal.DataManager;
47
import org.gvsig.fmap.dal.DataServerExplorer;
48
import org.gvsig.fmap.dal.DataStore;
49
import org.gvsig.fmap.dal.DataStoreNotification;
50
import org.gvsig.fmap.dal.DataTypes;
51
import org.gvsig.fmap.dal.FileHelper;
52
import org.gvsig.fmap.dal.exception.DataException;
53
import org.gvsig.fmap.dal.exception.InitializeException;
54
import org.gvsig.fmap.dal.exception.OpenException;
55
import org.gvsig.fmap.dal.exception.ReadException;
56
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
57 41335 jjdelcerro
import org.gvsig.fmap.dal.feature.EditableFeature;
58 41006 jjdelcerro
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
59 40846 jjdelcerro
import org.gvsig.fmap.dal.feature.EditableFeatureType;
60 41059 jjdelcerro
import org.gvsig.fmap.dal.feature.Feature;
61 41006 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
62 41335 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureAttributeEmulator;
63 41006 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureSet;
64 41059 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureStore;
65 40846 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureType;
66 41006 jjdelcerro
import org.gvsig.fmap.dal.feature.exception.PerformEditingException;
67 40846 jjdelcerro
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
68
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProviderServices;
69
import org.gvsig.fmap.dal.feature.spi.memory.AbstractMemoryStoreProvider;
70 41006 jjdelcerro
import org.gvsig.fmap.dal.resource.ResourceAction;
71 40846 jjdelcerro
import org.gvsig.fmap.dal.resource.file.FileResource;
72
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
73
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
74
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorer;
75
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorerParameters;
76
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
77 41617 jjdelcerro
import org.gvsig.fmap.dal.store.csv.simplereaders.CSVReader;
78
import org.gvsig.fmap.dal.store.csv.simplereaders.FixedLenReader;
79
import org.gvsig.fmap.dal.store.csv.simplereaders.SimpleReader;
80 40846 jjdelcerro
import org.gvsig.fmap.geom.Geometry;
81
import org.gvsig.fmap.geom.GeometryLocator;
82
import org.gvsig.fmap.geom.GeometryManager;
83 41335 jjdelcerro
import org.gvsig.fmap.geom.aggregate.MultiPoint;
84 40846 jjdelcerro
import org.gvsig.fmap.geom.primitive.Envelope;
85 41006 jjdelcerro
import org.gvsig.fmap.geom.primitive.Point;
86
import org.gvsig.fmap.geom.type.GeometryType;
87 40846 jjdelcerro
import org.gvsig.tools.ToolsLocator;
88
import org.gvsig.tools.dataTypes.CoercionException;
89 41335 jjdelcerro
import org.gvsig.tools.dataTypes.DataType;
90 41006 jjdelcerro
import org.gvsig.tools.dataTypes.DataTypesManager;
91 40846 jjdelcerro
import org.gvsig.tools.dataTypes.DataTypesManager.Coercion;
92 41069 jjdelcerro
import org.gvsig.tools.dataTypes.DataTypesManager.CoercionWithLocale;
93 41006 jjdelcerro
import org.gvsig.tools.dispose.DisposableIterator;
94 40846 jjdelcerro
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
95 41006 jjdelcerro
import org.gvsig.tools.evaluator.AbstractEvaluator;
96
import org.gvsig.tools.evaluator.EvaluatorData;
97
import org.gvsig.tools.evaluator.EvaluatorException;
98 41059 jjdelcerro
import org.gvsig.tools.exception.BaseException;
99 40846 jjdelcerro
import org.gvsig.tools.exception.NotYetImplemented;
100
import org.gvsig.tools.persistence.PersistentState;
101
import org.gvsig.tools.persistence.exception.PersistenceException;
102
import org.gvsig.tools.task.SimpleTaskStatus;
103
import org.gvsig.tools.task.TaskStatusManager;
104 41059 jjdelcerro
import org.gvsig.tools.visitor.VisitCanceledException;
105
import org.gvsig.tools.visitor.Visitor;
106 40846 jjdelcerro
import org.slf4j.Logger;
107
import org.slf4j.LoggerFactory;
108 41006 jjdelcerro
import org.supercsv.io.CsvListWriter;
109 40878 jjdelcerro
import org.supercsv.prefs.CsvPreference;
110 40846 jjdelcerro
111
public class CSVStoreProvider extends AbstractMemoryStoreProvider implements
112 41617 jjdelcerro
        ResourceConsumer {
113
114 40846 jjdelcerro
    private static final Logger logger = LoggerFactory.getLogger(CSVStoreProvider.class);
115
116
    public static final String NAME = "CSV";
117
    public static final String DESCRIPTION = "CSV file";
118
119
    public static final String METADATA_DEFINITION_NAME = NAME;
120
121
    private ResourceProvider resource;
122
123
    private long counterNewsOIDs = 0;
124
    private Envelope envelope;
125 41059 jjdelcerro
    private boolean need_calculate_envelope = false;
126 40846 jjdelcerro
    private SimpleTaskStatus taskStatus;
127
128
    public CSVStoreProvider(CSVStoreParameters parameters,
129 41617 jjdelcerro
            DataStoreProviderServices storeServices) throws InitializeException {
130 40846 jjdelcerro
        super(
131 41617 jjdelcerro
                parameters,
132
                storeServices,
133
                FileHelper.newMetadataContainer(METADATA_DEFINITION_NAME)
134 40846 jjdelcerro
        );
135
136
        TaskStatusManager manager = ToolsLocator.getTaskStatusManager();
137
        this.taskStatus = manager.createDefaultSimpleTaskStatus("CSV");
138
139
        counterNewsOIDs = 0;
140
141
        File file = getCSVParameters().getFile();
142
        resource = this.createResource(
143 41617 jjdelcerro
                FileResource.NAME,
144
                new Object[]{file.getAbsolutePath()}
145 40846 jjdelcerro
        );
146
147
        resource.addConsumer(this);
148 41006 jjdelcerro
        initializeFeatureTypes();
149 40846 jjdelcerro
    }
150
151
    private CSVStoreParameters getCSVParameters() {
152
        return (CSVStoreParameters) this.getParameters();
153
    }
154
155
    public String getProviderName() {
156
        return NAME;
157
    }
158
159
    public boolean allowWrite() {
160 41084 jjdelcerro
        return false;
161 40846 jjdelcerro
    }
162
163 41006 jjdelcerro
    private String getFullFileName() {
164 41617 jjdelcerro
        // Usar solo para mostrar mensajes en el logger.
165
        String s = "(unknow)";
166
        try {
167
            s = getCSVParameters().getFile().getAbsolutePath();
168
        } catch (Exception e2) {
169
            s = "(unknow)";
170
        }
171
        return s;
172 41006 jjdelcerro
    }
173 41617 jjdelcerro
174 40846 jjdelcerro
    public void open() throws OpenException {
175 42775 jjdelcerro
        if (this.data != null) {
176 40846 jjdelcerro
            return;
177
        }
178 43215 jjdelcerro
        this.data = new ArrayList<>();
179 41006 jjdelcerro
        resource.setData(new HashMap());
180
        counterNewsOIDs = 0;
181 41617 jjdelcerro
        try {
182
            loadFeatures();
183
        } catch (RuntimeException e) {
184 43215 jjdelcerro
            logger.debug("Can't load features from CSV '" + getFullFileName() + "'.", e);
185 41617 jjdelcerro
            throw e;
186
        } catch (Exception e) {
187 43215 jjdelcerro
            logger.debug("Can't load features from CSV '" + getFullFileName() + "'.", e);
188 41617 jjdelcerro
            throw new RuntimeException(e);
189
        }
190 40846 jjdelcerro
    }
191
192
    public DataServerExplorer getExplorer() throws ReadException {
193
        DataManager manager = DALLocator.getDataManager();
194 41006 jjdelcerro
        FilesystemServerExplorerParameters params;
195 40846 jjdelcerro
        try {
196
            params = (FilesystemServerExplorerParameters) manager
197 41617 jjdelcerro
                    .createServerExplorerParameters(FilesystemServerExplorer.NAME);
198 40846 jjdelcerro
            params.setRoot(this.getCSVParameters().getFile().getParent());
199 41617 jjdelcerro
            return manager.openServerExplorer(FilesystemServerExplorer.NAME, params);
200 40846 jjdelcerro
        } catch (DataException e) {
201
            throw new ReadException(this.getProviderName(), e);
202
        } catch (ValidateDataParametersException e) {
203
            throw new ReadException(this.getProviderName(), e);
204
        }
205
206
    }
207
208 41006 jjdelcerro
    class Writer {
209 41617 jjdelcerro
210
        private Envelope envelope = null;
211
        private boolean calculate_envelope = false;
212
        private CsvListWriter listWriter = null;
213
        private CsvPreference csvpreferences = null;
214
        private FileWriter fwriter = null;
215
        private FeatureType ftype;
216
        private File file;
217
        private String[] values;
218
        private FeatureAttributeDescriptor[] descriptors;
219
        private Coercion convert = null;
220
        private int errorcounts = 0;
221
        private Throwable lasterror = null;
222
        private Locale locale = null;
223
224
        public void initialize(File file, FeatureType ftype, CsvPreference csvpreferences) {
225
            this.file = file;
226
            this.ftype = ftype;
227
            this.csvpreferences = csvpreferences;
228
            this.locale = CSVStoreParameters.getLocale(getCSVParameters());
229 42775 jjdelcerro
            if (csvpreferences == null) {
230 41617 jjdelcerro
                this.csvpreferences = CsvPreference.STANDARD_PREFERENCE;
231
            }
232 42775 jjdelcerro
            if (ftype.getDefaultGeometryAttributeName() != null) {
233 41617 jjdelcerro
                this.calculate_envelope = true;
234
            }
235
            this.descriptors = this.ftype.getAttributeDescriptors();
236
            this.convert = ToolsLocator.getDataTypesManager().getCoercion(org.gvsig.tools.dataTypes.DataTypes.STRING);
237
            this.errorcounts = 0;
238
        }
239
240
        public void begin() {
241 41006 jjdelcerro
            try {
242 41617 jjdelcerro
                this.fwriter = new FileWriter(file);
243
            } catch (IOException e) {
244
                logger.warn("Can't open file for write (" + file.getAbsolutePath() + ").", e);
245
                throw new RuntimeException(e);
246
            }
247
            this.listWriter = new CsvListWriter(this.fwriter, this.csvpreferences);
248
            int n = 0;
249 42775 jjdelcerro
            for (int i = 0; i < descriptors.length; i++) {
250 41617 jjdelcerro
                FeatureAttributeDescriptor descriptor = descriptors[i];
251 42775 jjdelcerro
                if (descriptor.getEvaluator() == null) {
252 41617 jjdelcerro
                    n++;
253
                }
254
            }
255
256
            String[] header = new String[n];
257
            this.values = new String[n];
258
            n = 0;
259 42775 jjdelcerro
            for (int i = 0; i < descriptors.length; i++) {
260 41617 jjdelcerro
                FeatureAttributeDescriptor descriptor = descriptors[i];
261 42775 jjdelcerro
                if (descriptor.getEvaluator() == null) {
262 41617 jjdelcerro
                    String name = descriptor.getName();
263
                    String typeName = descriptor.getDataTypeName();
264 42775 jjdelcerro
                    if (descriptor.getDataType().getType() == DataTypes.STRING) {
265 41617 jjdelcerro
                        header[n++] = name + "__" + typeName + "__" + descriptor.getSize();
266
                    } else {
267
                        header[n++] = name + "__" + typeName;
268
                    }
269
                }
270
            }
271
            try {
272
                listWriter.writeHeader(header);
273
            } catch (Exception e) {
274
                logger.warn("Can't write header '" + header.toString() + "' file for write (" + file.getAbsolutePath() + ").", e);
275
                throw new RuntimeException(e);
276
            }
277
        }
278
279
        public void add(FeatureProvider feature) {
280 42775 jjdelcerro
            if (this.calculate_envelope) {
281 41617 jjdelcerro
                Geometry geom = feature.getDefaultGeometry();
282 42775 jjdelcerro
                if (geom != null) {
283
                    if (envelope == null) {
284 41617 jjdelcerro
                        try {
285
                            envelope = (Envelope) geom.getEnvelope().clone();
286
                        } catch (CloneNotSupportedException e) {
287
                            logger.warn("Este error no deberia pasar, siempre se puede hacer un clone de un envelope.", e);
288
                        }
289
                    } else {
290
                        envelope.add(geom.getEnvelope());
291
                    }
292
                }
293
            }
294
            int n = 0;
295 42775 jjdelcerro
            for (int i = 0; i < descriptors.length; i++) {
296 41617 jjdelcerro
                FeatureAttributeDescriptor descriptor = descriptors[i];
297 42775 jjdelcerro
                if (descriptor.getEvaluator() == null) {
298 41617 jjdelcerro
                    Object value = feature.get(i);
299
                    try {
300
                        n++;
301 42775 jjdelcerro
                        if (this.convert != null && this.convert instanceof CoercionWithLocale) {
302 41617 jjdelcerro
                            values[n] = (String) ((CoercionWithLocale) this.convert).coerce(value, this.locale);
303
                        } else {
304
                            values[n] = (String) this.convert.coerce(value);
305
                        }
306
                    } catch (CoercionException e) {
307
                        try {
308
                            values[n] = value.toString();
309
                        } catch (Exception ex) {
310
                            values[n] = "";
311
                        }
312 42775 jjdelcerro
                        if (errorcounts++ <= 10) {
313 41617 jjdelcerro
                            this.lasterror = e;
314
                            logger.warn("Can't convert value of field " + i + " to string in CVS file '" + getFullFileName() + "'.", e);
315 42775 jjdelcerro
                            if (errorcounts == 10) {
316 41617 jjdelcerro
                                logger.warn("Too many error writing CVS file '" + getFullFileName() + "', don't output more.");
317
                            }
318
                        }
319
                    }
320
                }
321
            }
322
            try {
323
                this.listWriter.writeHeader(values);
324
            } catch (IOException e) {
325 42775 jjdelcerro
                if (errorcounts++ <= 10) {
326 41617 jjdelcerro
                    this.lasterror = e;
327
                    logger.warn("Can't write values to CVS file '" + getFullFileName() + "'.", e);
328 42775 jjdelcerro
                    if (errorcounts == 10) {
329 41617 jjdelcerro
                        logger.warn("Too many error writing CVS file '" + getFullFileName() + "', don't output more.");
330
                    }
331
                }
332
            }
333
334
        }
335
336
        public void end() throws PerformEditingException {
337 42775 jjdelcerro
            if (this.errorcounts > 0) {
338 41617 jjdelcerro
                throw new PerformEditingException(this.file.getAbsolutePath(), lasterror);
339
            }
340 42775 jjdelcerro
            if (listWriter != null) {
341 41617 jjdelcerro
                try {
342
                    listWriter.close();
343
                } catch (Exception ex) {
344
                    // Ignore error
345
                }
346
                listWriter = null;
347
            }
348 42775 jjdelcerro
            if (fwriter != null) {
349 41617 jjdelcerro
                try {
350
                    fwriter.close();
351
                } catch (Exception ex) {
352
                    // Ignore error
353
                }
354
                fwriter = null;
355
            }
356
        }
357
358
        public Envelope getEnvelope() {
359
            return this.envelope;
360
        }
361 41006 jjdelcerro
    }
362 40846 jjdelcerro
363
    public void performChanges(Iterator deleteds, Iterator inserteds, Iterator updateds, Iterator originalFeatureTypesUpdated) throws PerformEditingException {
364
365
        try {
366
            this.taskStatus.add();
367
            taskStatus.message("_preparing");
368
            getResource().execute(new ResourceAction() {
369
                public Object run() throws Exception {
370
                    FeatureSet features = null;
371
                    DisposableIterator it = null;
372
                    try {
373
                        File file = (File) resource.get();
374 41617 jjdelcerro
375 41006 jjdelcerro
                        Writer writer = new Writer();
376 41617 jjdelcerro
                        writer.initialize(file, getStoreServices().getDefaultFeatureType(), getCSVPreferences());
377
                        features
378
                                = getStoreServices().getFeatureStore()
379
                                .getFeatureSet();
380 41006 jjdelcerro
                        List<FeatureProvider> newdata = new ArrayList<FeatureProvider>();
381 40846 jjdelcerro
                        writer.begin();
382
                        it = features.fastIterator();
383 41617 jjdelcerro
                        taskStatus.setRangeOfValues(0, 0);
384
                        long counter = 0;
385 42775 jjdelcerro
                        while (it.hasNext()) {
386 40846 jjdelcerro
                            taskStatus.setCurValue(counter++);
387
                            FeatureProvider feature = getStoreServices().getFeatureProviderFromFeature(
388 41617 jjdelcerro
                                    (org.gvsig.fmap.dal.feature.Feature) it.next());
389 40846 jjdelcerro
                            writer.add(feature);
390 42775 jjdelcerro
                            if (feature.getOID() == null) {
391 40846 jjdelcerro
                                logger.warn("feature without OID");
392
                                feature.setOID(createNewOID());
393
                            }
394
                            newdata.add(feature);
395
                        }
396
                        data = newdata;
397 42775 jjdelcerro
                        if (writer.getEnvelope() != null) {
398 40846 jjdelcerro
                            envelope = writer.getEnvelope().getGeometry().getEnvelope();
399
                        }
400
                        resource.notifyChanges();
401 41006 jjdelcerro
                        writer.end();
402 40846 jjdelcerro
                    } finally {
403 42775 jjdelcerro
                        if (it != null) {
404 40846 jjdelcerro
                            it.dispose();
405
                        }
406 42775 jjdelcerro
                        if (features != null) {
407 40846 jjdelcerro
                            features.dispose();
408
                        }
409
                    }
410
                    return null;
411
                }
412 41617 jjdelcerro
413
                private CsvPreference getCSVPreferences() {
414
                    CSVReader reader = new CSVReader(getCSVParameters());
415
                    return reader.getCSVPreferences();
416
                }
417 42220 fdiaz
418 40846 jjdelcerro
            });
419
            this.taskStatus.terminate();
420
        } catch (Exception e) {
421
            this.taskStatus.abort();
422
            throw new PerformEditingException(getResource().toString(), e);
423
        } finally {
424
            this.taskStatus.remove();
425
        }
426
    }
427
428
    public boolean closeResourceRequested(ResourceProvider resource) {
429
        return true;
430
    }
431
432
    public int getOIDType() {
433
        return DataTypes.LONG;
434
    }
435
436
    public boolean supportsAppendMode() {
437
        return false;
438
    }
439
440
    public void append(FeatureProvider featureProvider) {
441 41617 jjdelcerro
        throw new UnsupportedOperationException();
442 40846 jjdelcerro
    }
443
444
    public void beginAppend() {
445 41617 jjdelcerro
        throw new UnsupportedOperationException();
446 40846 jjdelcerro
    }
447
448
    public void endAppend() {
449 41617 jjdelcerro
        throw new UnsupportedOperationException();
450 40846 jjdelcerro
    }
451
452
    public void saveToState(PersistentState state) throws PersistenceException {
453
        throw new NotYetImplemented();
454
    }
455
456
    public void loadFromState(PersistentState state) throws PersistenceException {
457
        throw new NotYetImplemented();
458
    }
459
460
    public Object createNewOID() {
461
        return new Long(counterNewsOIDs++);
462
    }
463
464
    protected void initializeFeatureTypes() throws InitializeException {
465
        try {
466
            this.open();
467
        } catch (OpenException e) {
468
            throw new InitializeException(this.getProviderName(), e);
469
        }
470
    }
471
472
    public Envelope getEnvelope() throws DataException {
473
        this.open();
474 42775 jjdelcerro
        if (this.envelope != null) {
475 41617 jjdelcerro
            return this.envelope;
476 41059 jjdelcerro
        }
477 42775 jjdelcerro
        if (!this.need_calculate_envelope) {
478 41617 jjdelcerro
            return null;
479 41059 jjdelcerro
        }
480
        FeatureStore fs = this.getFeatureStore();
481
        FeatureType ft = fs.getDefaultFeatureType();
482
        FeatureAttributeDescriptor fad = ft.getAttributeDescriptor(ft.getDefaultGeometryAttributeIndex());
483
484
        try {
485
            this.envelope = GeometryLocator.getGeometryManager().createEnvelope(fad.getGeomType().getSubType());
486 41617 jjdelcerro
            fs.accept(new Visitor() {
487
                public void visit(Object obj) throws VisitCanceledException, BaseException {
488
                    Feature f = (Feature) obj;
489
                    Geometry geom = f.getDefaultGeometry();
490 42775 jjdelcerro
                    if (geom != null) {
491 41617 jjdelcerro
                        envelope.add(geom.getEnvelope());
492
                    }
493
                }
494
            });
495
        } catch (BaseException e) {
496
            logger.warn("Can't calculate the envelope of CSV file '" + this.getFullName() + "'.", e);
497
            this.envelope = null;
498
        }
499
500 41059 jjdelcerro
        this.need_calculate_envelope = false;
501 40846 jjdelcerro
        return this.envelope;
502
    }
503
504
    public Object getDynValue(String name) throws DynFieldNotFoundException {
505 42775 jjdelcerro
        if (DataStore.METADATA_ENVELOPE.equalsIgnoreCase(name)) {
506 40846 jjdelcerro
            try {
507
                return this.getEnvelope();
508
            } catch (DataException e) {
509
                return null;
510
            }
511
        } else {
512 42775 jjdelcerro
            if (DataStore.METADATA_CRS.equalsIgnoreCase(name)) {
513 40878 jjdelcerro
                IProjection pro = CSVStoreParameters.getCRS(this.getCSVParameters());
514 42775 jjdelcerro
                if (pro != null) {
515 40846 jjdelcerro
                    return pro;
516
                }
517
            }
518
        }
519
        return super.getDynValue(name);
520
    }
521
522
    public void resourceChanged(ResourceProvider resource) {
523
        this.getStoreServices().notifyChange(
524 41617 jjdelcerro
                DataStoreNotification.RESOURCE_CHANGED,
525
                resource);
526 40846 jjdelcerro
    }
527
528
    public Object getSourceId() {
529
        return this.getCSVParameters().getFile();
530
    }
531
532
    public String getName() {
533 40878 jjdelcerro
        String name = this.getCSVParameters().getFile().getName();
534 41006 jjdelcerro
        return FilenameUtils.getBaseName(name);
535 40846 jjdelcerro
    }
536
537
    public String getFullName() {
538
        return this.getCSVParameters().getFile().getAbsolutePath();
539
    }
540
541
    public ResourceProvider getResource() {
542
        return resource;
543
    }
544
545
    private boolean isEmpty(String s) {
546 42775 jjdelcerro
        if (s == null) {
547 41617 jjdelcerro
            return true;
548
        }
549
        return s.trim().length() == 0;
550 40846 jjdelcerro
    }
551 40878 jjdelcerro
552 41335 jjdelcerro
    private class FieldTypeParser {
553 41617 jjdelcerro
554 41335 jjdelcerro
        public String name = null;
555
        public int type = DataTypes.STRING;
556
        public int size = 0;
557
        public boolean allowNulls = true;
558 41876 jjdelcerro
        public int geometryType = Geometry.TYPES.GEOMETRY;
559 41335 jjdelcerro
560
        private String typename = "string";
561 41617 jjdelcerro
562 41335 jjdelcerro
        FieldTypeParser() {
563
        }
564 41617 jjdelcerro
565 41335 jjdelcerro
        private int getType(String value) {
566 41617 jjdelcerro
            DataTypesManager dataTypesManager = ToolsLocator.getDataTypesManager();
567 41335 jjdelcerro
            return dataTypesManager.getType(typename);
568
        }
569 41617 jjdelcerro
570 42775 jjdelcerro
        public void clear() {
571
            name = null;
572
            type = DataTypes.STRING;
573
            size = 0;
574
            allowNulls = true;
575
            geometryType = Geometry.TYPES.GEOMETRY;
576
        }
577
578
        public void copyFrom(FieldTypeParser other) {
579
            name = other.name;
580
            type = other.type;
581
            size = other.size;
582
            allowNulls = other.allowNulls;
583
            geometryType = other.geometryType;
584
        }
585
586 41335 jjdelcerro
        // El formato seria:
587
        //   name[:typename[:size[:notnull|null]]]
588 41876 jjdelcerro
        //   name[:GEOMETRY[:geometry_type[:notnull|null]]]
589 41335 jjdelcerro
        //   name[__typename[__size[__notnull|null]]]
590
        //
591
        public boolean parse(String value) {
592
            String typename = null;
593
            String[] ss = null;
594 42775 jjdelcerro
            if (value.contains(":")) {
595 41335 jjdelcerro
                ss = value.split(":");
596 42775 jjdelcerro
            } else if (value.contains("__")) {
597 41335 jjdelcerro
                ss = value.split("__");
598
            }
599 42775 jjdelcerro
            if (ss == null) {
600 41335 jjdelcerro
                this.name = value;
601
                return true;
602
            }
603 41617 jjdelcerro
            switch (ss.length) {
604 42775 jjdelcerro
                case 4:
605
                    if (!StringUtils.isBlank(ss[3])) {
606
                        if ("notnull".equalsIgnoreCase(ss[3].trim())) {
607
                            this.allowNulls = false;
608
                        } else {
609
                            this.allowNulls = true;
610
                        }
611 41335 jjdelcerro
                    }
612 42775 jjdelcerro
                case 3:
613
                    if (!StringUtils.isBlank(ss[1])) {
614
                        this.typename = ss[1].trim();
615
                        this.type = this.getType(this.typename);
616
                        if (this.type == DataTypes.INVALID) {
617
                            this.type = DataTypes.STRING;
618
                            logger.info("Type '" + typename + "' not valid for attribute '" + value + "' in CSV file '" + getFullFileName() + "'.");
619
                        }
620 41335 jjdelcerro
                    }
621 42775 jjdelcerro
                    if (!StringUtils.isBlank(ss[2])) {
622
                        if (this.type == DataTypes.GEOMETRY) {
623
                            String s = ss[2].trim();
624
                            if (s.equalsIgnoreCase("line") || s.equalsIgnoreCase("linestring") || s.equalsIgnoreCase("curve")) {
625 43510 jjdelcerro
                                this.geometryType = Geometry.TYPES.LINE;
626 42775 jjdelcerro
                            } else if (s.equalsIgnoreCase("multiline") || s.equalsIgnoreCase("multilinestring") || s.equalsIgnoreCase("multicurve")) {
627 43510 jjdelcerro
                                this.geometryType = Geometry.TYPES.MULTILINE;
628 42775 jjdelcerro
                            } else if (s.equalsIgnoreCase("point")) {
629
                                this.geometryType = Geometry.TYPES.POINT;
630
                            } else if (s.equalsIgnoreCase("multipoint")) {
631
                                this.geometryType = Geometry.TYPES.MULTIPOINT;
632
                            } else if (s.equalsIgnoreCase("polygon") || s.equalsIgnoreCase("surface")) {
633
                                this.geometryType = Geometry.TYPES.POLYGON;
634
                            } else if (s.equalsIgnoreCase("multipolygon") || s.equalsIgnoreCase("multisurface")) {
635 43510 jjdelcerro
                                this.geometryType = Geometry.TYPES.MULTIPOLYGON;
636 42775 jjdelcerro
                            }
637
                            this.size = 1;
638
                        } else {
639
                            try {
640
                                this.size = Integer.parseInt(ss[2]);
641
                            } catch (Exception ex) {
642
                                logger.warn("Ignore incorrect field size for field " + value + " in CSV header of '" + getFullFileName() + "'.", ex);
643
                            }
644 41876 jjdelcerro
                        }
645 42775 jjdelcerro
                    }
646
                    this.name = ss[0].trim();
647
                    break;
648
                case 2:
649
                    if (!StringUtils.isBlank(ss[1])) {
650
                        this.typename = ss[1].trim();
651
                        this.type = this.getType(this.typename);
652
                        if (this.type == DataTypes.INVALID) {
653
                            this.type = DataTypes.STRING;
654
                            logger.info("Type '" + typename + "' not valid for attribute '" + value + "' in CSV file '" + getFullFileName() + "'.");
655 41876 jjdelcerro
                        }
656
                    }
657 42775 jjdelcerro
                case 1:
658
                    this.name = ss[0].trim();
659
                    break;
660 41335 jjdelcerro
            }
661 41617 jjdelcerro
662 42775 jjdelcerro
            if (this.type != DataTypes.STRING) {
663 41335 jjdelcerro
                this.size = 0;
664
            }
665
            return true;
666
        }
667 41617 jjdelcerro
668 41335 jjdelcerro
    }
669 41617 jjdelcerro
670 41062 jjdelcerro
    private EditableFeatureType getFeatureType(String headers[], int automaticTypes[]) {
671 41335 jjdelcerro
        EditableFeatureType fType = getStoreServices().createFeatureType(this.getName());
672
        fType.setHasOID(true);
673
674
        FieldTypeParser[] fieldTypes = new FieldTypeParser[headers.length];
675 41617 jjdelcerro
        //
676 41335 jjdelcerro
        // Calculamos cuales pueden ser los tipos de datos
677
        //
678 42775 jjdelcerro
        for (int i = 0; i < fieldTypes.length; i++) {
679 41335 jjdelcerro
            fieldTypes[i] = new FieldTypeParser();
680
        }
681
682 41617 jjdelcerro
        // Asuminos los tipos pasados por parametro, que se supone
683 41335 jjdelcerro
        // son los detectados automaticamente.
684 42775 jjdelcerro
        if (automaticTypes != null) {
685
            for (int i = 0; i < fieldTypes.length && i < automaticTypes.length; i++) {
686 41335 jjdelcerro
                fieldTypes[i].type = automaticTypes[i];
687
            }
688
        }
689
        // Luego probamos con lo que diga las cabezeras del CVS, sobreescribiendo
690
        // los tipos anteriores en caso de definirse en la cabezara.
691 42775 jjdelcerro
        for (int i = 0; i < fieldTypes.length; i++) {
692
            if (!fieldTypes[i].parse(headers[i])) {
693 41335 jjdelcerro
                continue;
694
            }
695
696
        }
697
698 41617 jjdelcerro
        // Y por ultimo hacemos caso a lo que se haya especificado en los parametros
699 41335 jjdelcerro
        // de apertura del CSV, teniendo esto prioridad sobre todo.
700 41876 jjdelcerro
        String param_types_def = CSVStoreParameters.getRawFieldTypes(this.getParameters());
701 41901 jjdelcerro
        if (StringUtils.isNotBlank(param_types_def)) {
702
            String sep = CSVStoreParameters.getDelimiter(param_types_def);
703 42775 jjdelcerro
            if (StringUtils.isNotBlank(sep)) {
704 41901 jjdelcerro
                String[] param_types = param_types_def.split(sep);
705 42775 jjdelcerro
                FieldTypeParser parser = new FieldTypeParser();
706
                for (String param_type : param_types) {
707
                    parser.clear();
708
                    parser.parse(param_type);
709
                    for (FieldTypeParser fieldType : fieldTypes) {
710
                        if (StringUtils.equalsIgnoreCase(fieldType.name, parser.name)) {
711
                            fieldType.copyFrom(parser);
712
                            break;
713
                        }
714 41901 jjdelcerro
                    }
715 41335 jjdelcerro
                }
716
            }
717
        }
718 41617 jjdelcerro
        //
719 41335 jjdelcerro
        // Una vez ya sabemos los tipos de datos rellenamos el feature-type
720
        //
721 42775 jjdelcerro
        for (int i = 0; i < fieldTypes.length; i++) {
722 41335 jjdelcerro
            EditableFeatureAttributeDescriptor fad = fType.add(
723
                    fieldTypes[i].name,
724
                    fieldTypes[i].type
725
            );
726
            fad.setSize(fieldTypes[i].size);
727
            fad.setAllowNull(fieldTypes[i].allowNulls);
728 42775 jjdelcerro
            if (fieldTypes[i].type == DataTypes.GEOMETRY) {
729
                if (fType.getDefaultGeometryAttributeName() == null) {
730 41876 jjdelcerro
                    fType.setDefaultGeometryAttributeName(fieldTypes[i].name);
731
                }
732
                fad.setGeometryType(fieldTypes[i].geometryType);
733 41335 jjdelcerro
            }
734
        }
735
        String[] pointDimensionNames = CSVStoreParameters.getPointDimensionNames(this.getParameters());
736 42775 jjdelcerro
        if (pointDimensionNames != null) {
737 41335 jjdelcerro
            PointAttributeEmulator emulator = new PointAttributeEmulator(pointDimensionNames);
738 42775 jjdelcerro
            EditableFeatureAttributeDescriptor attr = fType.add(
739
                    CSVStoreParameters.getPointColumnName(this.getParameters()),
740
                    DataTypes.GEOMETRY, emulator
741
            );
742 41335 jjdelcerro
            GeometryManager geommgr = GeometryLocator.getGeometryManager();
743
            GeometryType gt;
744
            try {
745
                gt = geommgr.getGeometryType(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D);
746
                attr.setGeometryType(gt);
747 41635 jjdelcerro
                attr.setGeometryType(Geometry.TYPES.POINT);
748 42220 fdiaz
                attr.setGeometrySubType(Geometry.SUBTYPES.GEOM3D);
749 41335 jjdelcerro
            } catch (Exception e) {
750
                logger.warn("Can't set geometry type for the calculated field in CSV file '" + getFullFileName() + "'.", e);
751
            }
752
        }
753 43283 jjdelcerro
754
        String geometry_column = CSVStoreParameters.getGeometryColumn(this.getParameters());
755
        if( !StringUtils.isEmpty(geometry_column) ) {
756
            EditableFeatureAttributeDescriptor attr = (EditableFeatureAttributeDescriptor) fType.get(geometry_column);
757
            if( attr!=null && attr.getType()!=DataTypes.GEOMETRY ) {
758
                attr.setDataType(DataTypes.GEOMETRY);
759
                GeometryManager geommgr = GeometryLocator.getGeometryManager();
760
                GeometryType gt;
761
                try {
762
                    gt = geommgr.getGeometryType(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.UNKNOWN);
763
                    attr.setGeometryType(gt);
764
                } catch (Exception e) {
765
                    logger.warn("Can't set geometry type for the calculated field in CSV file '" + getFullFileName() + "'.", e);
766
                }
767
                fType.setDefaultGeometryAttributeName(geometry_column);
768
            }
769
        }
770 41335 jjdelcerro
        return fType;
771 40846 jjdelcerro
    }
772 41617 jjdelcerro
773 41335 jjdelcerro
    static class PointAttributeEmulator implements FeatureAttributeEmulator {
774
775
        private static final Logger logger = LoggerFactory.getLogger(ToPointEvaluaror.class);
776
777 41342 jjdelcerro
        private static final int XNAME = 0;
778
        private static final int YNAME = 1;
779
        private static final int ZNAME = 2;
780 41617 jjdelcerro
781 41335 jjdelcerro
        private final GeometryManager geommgr;
782 41342 jjdelcerro
        private final String[] fieldNames;
783 41335 jjdelcerro
        private final Coercion toDouble;
784
        private final DataType dataType;
785
        private int errorcount = 0;
786
787
        public PointAttributeEmulator(String[] pointDimensionNames) {
788 42775 jjdelcerro
            if (pointDimensionNames.length > 2) {
789 41342 jjdelcerro
                this.fieldNames = new String[3];
790
                this.fieldNames[ZNAME] = pointDimensionNames[2];
791 41335 jjdelcerro
            } else {
792 41342 jjdelcerro
                this.fieldNames = new String[2];
793 41335 jjdelcerro
            }
794 41342 jjdelcerro
            this.fieldNames[XNAME] = pointDimensionNames[0];
795
            this.fieldNames[YNAME] = pointDimensionNames[1];
796 41335 jjdelcerro
            this.geommgr = GeometryLocator.getGeometryManager();
797
            DataTypesManager datatypeManager = ToolsLocator.getDataTypesManager();
798
799
            this.toDouble = datatypeManager.getCoercion(DataTypes.DOUBLE);
800
            this.dataType = datatypeManager.get(DataTypes.GEOMETRY);
801
        }
802 41617 jjdelcerro
803 41335 jjdelcerro
        public Object get(Feature feature) {
804
            try {
805 41348 jjdelcerro
                Object valueX = feature.get(this.fieldNames[XNAME]);
806
                valueX = toDouble.coerce(valueX);
807 42775 jjdelcerro
                if (valueX == null) {
808 41348 jjdelcerro
                    return null;
809
                }
810
                Object valueY = feature.get(this.fieldNames[YNAME]);
811
                valueY = toDouble.coerce(valueY);
812 42775 jjdelcerro
                if (valueY == null) {
813 41348 jjdelcerro
                    return null;
814
                }
815
                Object valueZ = null;
816 42775 jjdelcerro
                if (this.fieldNames.length > 2) {
817 41348 jjdelcerro
                    valueZ = toDouble.coerce(feature.get(this.fieldNames[ZNAME]));
818 42775 jjdelcerro
                    if (valueZ == null) {
819 41348 jjdelcerro
                        return null;
820
                    }
821
                }
822 41617 jjdelcerro
823
                double x = ((Double) valueX).doubleValue();
824
                double y = ((Double) valueY).doubleValue();
825 41335 jjdelcerro
                Point point = geommgr.createPoint(x, y, Geometry.SUBTYPES.GEOM3D);
826 42775 jjdelcerro
                if (this.fieldNames.length > 2) {
827 41617 jjdelcerro
                    double z = ((Double) valueZ).doubleValue();
828 41335 jjdelcerro
                    point.setCoordinateAt(2, z);
829
                }
830
                return point;
831
            } catch (Exception ex) {
832 42775 jjdelcerro
                if (++errorcount < 5) {
833 41335 jjdelcerro
                    logger.warn("[" + errorcount + "] Can't create point in CSV provider. XNAME='"
834 41617 jjdelcerro
                            + this.fieldNames[XNAME] + "', YNAME='" + this.fieldNames[XNAME] + "' feature=" + feature.toString(), ex);
835 41335 jjdelcerro
                }
836
                return null;
837
            }
838
        }
839
840
        public void set(EditableFeature feature, Object value) {
841 42775 jjdelcerro
            if (value == null) {
842 41335 jjdelcerro
                return;
843
            }
844
            Point point = null;
845 42775 jjdelcerro
            if (value instanceof MultiPoint) {
846 41617 jjdelcerro
                point = (Point) ((MultiPoint) value).getPrimitiveAt(0);
847 41335 jjdelcerro
            } else {
848
                point = (Point) value;
849
            }
850 41342 jjdelcerro
            feature.set(this.fieldNames[XNAME], point.getX());
851
            feature.set(this.fieldNames[YNAME], point.getY());
852 42775 jjdelcerro
            if (this.fieldNames.length > 2) {
853 41342 jjdelcerro
                feature.set(this.fieldNames[ZNAME], point.getCoordinateAt(2));
854 41335 jjdelcerro
            }
855
        }
856
857
        public boolean allowSetting() {
858
            return true;
859
        }
860 41342 jjdelcerro
861
        public String[] getRequiredFieldNames() {
862
            return this.fieldNames;
863
        }
864 41617 jjdelcerro
865 41335 jjdelcerro
    }
866 41617 jjdelcerro
867 41006 jjdelcerro
    static class ToPointEvaluaror extends AbstractEvaluator {
868 40846 jjdelcerro
869 41335 jjdelcerro
        private static final Logger logger = LoggerFactory.getLogger(ToPointEvaluaror.class);
870 40846 jjdelcerro
871 41335 jjdelcerro
        private GeometryManager geommgr = null;
872
        private String xname = null;
873
        private String yname = null;
874
        private String zname = null;
875
        private Coercion toDouble;
876
        private int errorcount = 0;
877
878
        ToPointEvaluaror(String[] pointDimensionNames) {
879
            this.xname = pointDimensionNames[0];
880
            this.yname = pointDimensionNames[1];
881 42775 jjdelcerro
            if (pointDimensionNames.length > 2) {
882 41335 jjdelcerro
                this.zname = pointDimensionNames[2];
883
            }
884
            this.geommgr = GeometryLocator.getGeometryManager();
885
            this.toDouble = ToolsLocator.getDataTypesManager().getCoercion(DataTypes.DOUBLE);
886
        }
887
888
        public Object evaluate(EvaluatorData data) throws EvaluatorException {
889
            try {
890
                double x = ((Double) toDouble.coerce(data.getDataValue(xname))).doubleValue();
891
                double y = ((Double) toDouble.coerce(data.getDataValue(yname))).doubleValue();
892
                Point point = geommgr.createPoint(x, y, Geometry.SUBTYPES.GEOM3D);
893 42775 jjdelcerro
                if (zname != null) {
894 41335 jjdelcerro
                    double z = ((Double) toDouble.coerce(data.getDataValue(zname))).doubleValue();
895
                    point.setCoordinateAt(2, z);
896
                }
897
                return point;
898
            } catch (Exception ex) {
899 42775 jjdelcerro
                if (++errorcount < 5) {
900 41335 jjdelcerro
                    logger.warn("[" + errorcount + "] Can't create point in CSV provider. XNAME='"
901
                            + xname + "', YNAME='" + yname + "', ZNAME='" + zname + "', data=" + data.toString());
902
                }
903
                return null;
904
            }
905
        }
906
907
        public String getName() {
908
            return "ToPointEvaluaror";
909
        }
910
911 40846 jjdelcerro
    }
912 41335 jjdelcerro
913 43283 jjdelcerro
    private SimpleReader getSimpleReader(InputStreamReader in) {
914 41617 jjdelcerro
        SimpleReader reader;
915 42775 jjdelcerro
        if (CSVStoreParameters.getRawFieldsDefinition(getCSVParameters()) != null) {
916 41617 jjdelcerro
            reader = new FixedLenReader(in, getCSVParameters());
917
        } else {
918
            reader = new CSVReader(in, getCSVParameters());
919
        }
920
        return reader;
921
    }
922 41006 jjdelcerro
923 42775 jjdelcerro
    private String getFixedHeader(int column) {
924
        char[] header = new char[3];
925
926
        String s = String.format("%03d", column);
927
        header[0] = (char) (s.charAt(0) + 17);
928
        header[1] = (char) (s.charAt(1) + 17);
929
        header[2] = (char) (s.charAt(2) + 17);
930
        return String.valueOf(header);
931
    }
932
933
    private String[] getFixedHeaders(int count) {
934
        String[] headers = new String[count];
935
        for (int i = 0; i < headers.length; i++) {
936
            headers[i] = getFixedHeader(i);
937
        }
938
        return headers;
939
    }
940
941 43283 jjdelcerro
    private InputStreamReader openFile(File f, String charsetName) throws FileNotFoundException {
942
        Charset charset = Charset.defaultCharset();
943
        FileInputStream fis = new FileInputStream(f);
944
        if( !StringUtils.isEmpty(charsetName) ) {
945
            if( Charset.isSupported(charsetName) )  {
946
                try {
947
                    charset = Charset.forName(charsetName);
948
                } catch(Throwable th) {
949
                    logger.warn("Can't use charset '"+charsetName+"' for read csv '"+this.getFullFileName()+"'.", th);
950
                }
951
            } else {
952
                logger.warn("charset '"+charsetName+"' not supported for read csv '"+this.getFullFileName()+"'.");
953
            }
954
        }
955
        InputStreamReader isr = new InputStreamReader(fis, charset);
956
        return isr;
957
    }
958
959 42775 jjdelcerro
    private void loadFeatures() {
960 43283 jjdelcerro
        InputStreamReader in = null;
961 41617 jjdelcerro
        SimpleReader reader = null;
962
        try {
963
            String headers[] = null;
964
            FeatureStoreProviderServices store = this.getStoreServices();
965 41006 jjdelcerro
966 41617 jjdelcerro
            boolean ignore_errors = CSVStoreParameters.getIgnoreErrors(getCSVParameters());
967 42220 fdiaz
968 43283 jjdelcerro
            in = openFile(
969
                this.getCSVParameters().getFile(),
970
                CSVStoreParameters.getCharset(this.getCSVParameters())
971
            );
972 41006 jjdelcerro
973 41617 jjdelcerro
            reader = getSimpleReader(in);
974 41006 jjdelcerro
975 41617 jjdelcerro
            headers = CSVStoreParameters.getHeaders(getCSVParameters());
976 42775 jjdelcerro
            if (headers == null) {
977
                if (CSVStoreParameters.isFirstLineHeader(getCSVParameters())) {
978
                    headers = reader.getHeader();
979
                    if (headers == null) {
980
                        if (CSVStoreParameters.getIgnoreErrors(getCSVParameters())) {
981
                            headers = getFixedHeaders(reader.getColumnsCount());
982
                        } else {
983
                            String msg = "Can't retrieve header from csv file '"
984
                                    + this.getCSVParameters().getFile()
985
                                    .getAbsolutePath()
986
                                    + "' and not specified in the parameters.";
987
                            logger.warn(msg);
988
                            throw new RuntimeException(msg);
989
                        }
990
                    }
991
                } else {
992
                    headers = getFixedHeaders(reader.getColumnsCount());
993 41617 jjdelcerro
                }
994 42775 jjdelcerro
            } else {
995
                if (CSVStoreParameters.isFirstLineHeader(getCSVParameters())) {
996
                    reader.getHeader(); // Skip and ignore the header of file
997
                }
998 41617 jjdelcerro
            }
999 41006 jjdelcerro
1000 42775 jjdelcerro
            int[] detectedTypes = automaticDetectionOfTypes(headers);
1001
            if( detectedTypes!=null && detectedTypes.length>headers.length ) {
1002
                // Se han detectado mas columnas que las que hay en la cabezera,
1003
                // a?adimos mas columnas a la cabezera.
1004
                String[] headers2 = new String[detectedTypes.length];
1005
                for( int i=0; i<headers2.length; i++ ) {
1006
                    if( i<headers.length ) {
1007
                        headers2[i] = headers[i];
1008
                    } else {
1009
                        headers2[i] = getFixedHeader(i);
1010
                    }
1011
                }
1012
                headers = headers2;
1013
            }
1014 41617 jjdelcerro
            // Initialize the feature types
1015 42775 jjdelcerro
            EditableFeatureType edftype = this.getFeatureType(headers, detectedTypes);
1016 41617 jjdelcerro
            FeatureType ftype = edftype.getNotEditableCopy();
1017 42775 jjdelcerro
            List<FeatureType> ftypes = new ArrayList<>();
1018 41617 jjdelcerro
            ftypes.add(ftype);
1019
            store.setFeatureTypes(ftypes, ftype);
1020 41059 jjdelcerro
1021 41617 jjdelcerro
            Coercion coercion[] = new Coercion[ftype.size()];
1022
            int sizes[] = new int[ftype.size()];
1023 42775 jjdelcerro
            for (int i = 0; i < ftype.size(); i++) {
1024 41617 jjdelcerro
                sizes[i] = -1;
1025
                FeatureAttributeDescriptor ad = ftype.getAttributeDescriptor(i);
1026
                coercion[i] = ad.getDataType().getCoercion();
1027 43425 jjdelcerro
                switch (ad.getDataType().getType() ) {
1028
                case DataTypes.STRING:
1029 42775 jjdelcerro
                    if (ad.getSize() == 0) {
1030 41617 jjdelcerro
                        // Es un string y no tiene un size asignado.
1031
                        // Lo ponemos a cero para calcularlo.
1032
                        sizes[i] = 0;
1033
                    }
1034 43425 jjdelcerro
                    break;
1035
                case DataTypes.URL:
1036
                case DataTypes.URI:
1037
                case DataTypes.FILE:
1038
                    sizes[i] = 0;
1039 41617 jjdelcerro
                }
1040
            }
1041 42775 jjdelcerro
            if (ftype.getDefaultGeometryAttributeName() != null) {
1042 41617 jjdelcerro
                this.need_calculate_envelope = true;
1043
            }
1044 41006 jjdelcerro
1045 41617 jjdelcerro
            Locale locale = CSVStoreParameters.getLocale(getCSVParameters());
1046
            taskStatus.message("_loading");
1047
            int count = 0;
1048 41062 jjdelcerro
1049 41617 jjdelcerro
            int count_errors = 0;
1050 41062 jjdelcerro
1051 41617 jjdelcerro
            List<String> row = reader.read();
1052 41062 jjdelcerro
1053 41617 jjdelcerro
            int skipLines = CSVStoreParameters.getSkipLines(getCSVParameters());
1054 42775 jjdelcerro
            if (skipLines > 0) {
1055 41617 jjdelcerro
                row = reader.skip(skipLines);
1056
            }
1057 42775 jjdelcerro
            int limit = CSVStoreParameters.getLimit(getCSVParameters());
1058
            while (row != null) {
1059 41617 jjdelcerro
                taskStatus.setCurValue(++count);
1060
                FeatureProvider feature = this.createFeatureProvider(ftype);
1061 42775 jjdelcerro
                for (int i = 0; i < row.size(); i++) {
1062 41617 jjdelcerro
                    Object rawvalue = row.get(i);
1063
                    try {
1064
                        Object value = null;
1065 42775 jjdelcerro
                        if (locale != null && coercion[i] instanceof CoercionWithLocale) {
1066 41617 jjdelcerro
                            value = ((CoercionWithLocale) (coercion[i])).coerce(rawvalue, locale);
1067
                        } else {
1068
                            value = coercion[i].coerce(rawvalue);
1069 41199 jjdelcerro
                        }
1070 41617 jjdelcerro
                        feature.set(i, value);
1071 43425 jjdelcerro
                        if (sizes[i] >= 0 &&
1072
                            (value instanceof String || value instanceof URL ||
1073
                             value instanceof URI || value instanceof File) ) {
1074
                            int x = value.toString().length();
1075 42775 jjdelcerro
                            if (sizes[i] < x) {
1076 41617 jjdelcerro
                                sizes[i] = x;
1077
                            }
1078
                        }
1079 42775 jjdelcerro
                    } catch (Exception ex) {
1080
                        if (!ignore_errors) {
1081 41617 jjdelcerro
                            throw ex;
1082
                        }
1083 42775 jjdelcerro
                        if (count_errors++ < 10) {
1084 41617 jjdelcerro
                            logger.warn("Can't load value of attribute " + i + " in row " + count + ".", ex);
1085
                        }
1086 42775 jjdelcerro
                        if (count_errors == 10) {
1087 41617 jjdelcerro
                            logger.info("Too many errors, suppress messages.");
1088
                        }
1089
                    }
1090
                }
1091
                this.addFeatureProvider(feature);
1092 42775 jjdelcerro
                if( limit>0 ) {
1093
                    if( limit < this.data.size() ) {
1094
                        break;
1095
                    }
1096
                }
1097 41617 jjdelcerro
                row = reader.read();
1098
            }
1099 42775 jjdelcerro
            for (int i = 0; i < ftype.size(); i++) {
1100
                if (sizes[i] > 0) {
1101 41617 jjdelcerro
                    EditableFeatureAttributeDescriptor efad = ((EditableFeatureAttributeDescriptor) edftype.getAttributeDescriptor(i));
1102
                    efad.setSize(sizes[i]);
1103
                }
1104
            }
1105
            // Volvemos a asignar al store el featuretype, ya que puede
1106
            // haber cambiado.
1107
            ftype = edftype.getNotEditableCopy();
1108 42775 jjdelcerro
            ftypes = new ArrayList<>();
1109 41617 jjdelcerro
            ftypes.add(ftype);
1110
            store.setFeatureTypes(ftypes, ftype);
1111 41062 jjdelcerro
1112 41617 jjdelcerro
            taskStatus.terminate();
1113 42775 jjdelcerro
        } catch (Exception ex) {
1114 41643 jjdelcerro
            int lineno = 0;
1115 42775 jjdelcerro
            if (reader != null) {
1116 41643 jjdelcerro
                lineno = reader.getLine();
1117
            }
1118 42775 jjdelcerro
            throw new RuntimeException("Problems reading file '" + getFullFileName() + "' near line " + lineno + ".", ex);
1119 41643 jjdelcerro
1120 41617 jjdelcerro
        } finally {
1121 42775 jjdelcerro
            if (reader != null) {
1122 41617 jjdelcerro
                try {
1123
                    reader.close();
1124
                } catch (Exception ex) {
1125
                    // Do nothing
1126
                }
1127
                reader = null;
1128
            }
1129 42775 jjdelcerro
            if (in != null) {
1130 41617 jjdelcerro
                try {
1131
                    in.close();
1132
                } catch (Exception ex) {
1133
                    // Do nothing
1134
                }
1135
                in = null;
1136
            }
1137
        }
1138
    }
1139 41062 jjdelcerro
1140 42775 jjdelcerro
    private static class PossibleDataType {
1141
1142
        public boolean possibleInt = true;
1143
        public boolean possibleFloat = true;
1144
        public boolean possibleDouble = true;
1145
        public boolean possibleLong = true;
1146
        public boolean possibleURL = true;
1147
        public boolean possibleDate = true;
1148
        public boolean possibleGeometry = true;
1149
    }
1150
1151
    private int[] automaticDetectionOfTypes(String[] headers) throws IOException {
1152 41617 jjdelcerro
        boolean automatic_types_detection = CSVStoreParameters.getAutomaticTypesDetection(getCSVParameters());
1153 42775 jjdelcerro
        if (!automatic_types_detection) {
1154 41617 jjdelcerro
            return null;
1155
        }
1156 42775 jjdelcerro
        List<PossibleDataType> possibleDataTypes;
1157
        Locale locale;
1158 41617 jjdelcerro
        int[] types = null;
1159
1160
        FileReader in = null;
1161
        SimpleReader reader = null;
1162
1163
        try {
1164
            in = new FileReader(this.getCSVParameters().getFile());
1165
            reader = getSimpleReader(in);
1166 42775 jjdelcerro
            if (CSVStoreParameters.isFirstLineHeader(getCSVParameters())) {
1167
                reader.read();
1168 41617 jjdelcerro
            }
1169 42775 jjdelcerro
            possibleDataTypes = new ArrayList<>(headers.length);
1170
            for (String header : headers) {
1171
                possibleDataTypes.add(new PossibleDataType());
1172 41617 jjdelcerro
            }
1173
            locale = CSVStoreParameters.getLocale(getCSVParameters());
1174 42775 jjdelcerro
            if (locale == null) {
1175 41617 jjdelcerro
                locale = Locale.getDefault();
1176
            }
1177
            DataTypesManager typeManager = ToolsLocator.getDataTypesManager();
1178
            CoercionWithLocale toDouble = (CoercionWithLocale) typeManager.getCoercion(DataTypes.DOUBLE);
1179
            CoercionWithLocale toFloat = (CoercionWithLocale) typeManager.getCoercion(DataTypes.FLOAT);
1180 41688 jjdelcerro
            CoercionWithLocale toDate = (CoercionWithLocale) typeManager.getCoercion(DataTypes.DATE);
1181 42775 jjdelcerro
            CoercionWithLocale toInt = (CoercionWithLocale) typeManager.getCoercion(DataTypes.INT);
1182
            CoercionWithLocale toLong = (CoercionWithLocale) typeManager.getCoercion(DataTypes.LONG);
1183
            Coercion toGeom = typeManager.getCoercion(DataTypes.GEOMETRY);
1184 41617 jjdelcerro
1185
            List<String> row = reader.read();
1186
1187 42775 jjdelcerro
            while (row != null) {
1188
                for (int i = 0; i < row.size(); i++) {
1189
                    while( possibleDataTypes.size()<row.size() ) {
1190
                        possibleDataTypes.add(new PossibleDataType());
1191 41617 jjdelcerro
                    }
1192 42775 jjdelcerro
                    String rawvalue = row.get(i);
1193
                    PossibleDataType possibleDataType = possibleDataTypes.get(i);
1194
                    if (possibleDataType.possibleDouble) {
1195 41617 jjdelcerro
                        try {
1196 42775 jjdelcerro
                            toDouble.coerce(rawvalue, locale);
1197
                            possibleDataType.possibleDouble = true;
1198 41617 jjdelcerro
                        } catch (Exception ex) {
1199 42775 jjdelcerro
                            possibleDataType.possibleDouble = false;
1200 41617 jjdelcerro
                        }
1201
                    }
1202 42775 jjdelcerro
                    if (possibleDataType.possibleFloat) {
1203 41617 jjdelcerro
                        try {
1204 42775 jjdelcerro
                            toFloat.coerce(rawvalue, locale);
1205
                            possibleDataType.possibleFloat = true;
1206 41617 jjdelcerro
                        } catch (Exception ex) {
1207 42775 jjdelcerro
                            possibleDataType.possibleFloat = false;
1208 41617 jjdelcerro
                        }
1209
                    }
1210 42775 jjdelcerro
                    if (possibleDataType.possibleLong) {
1211
                        possibleDataType.possibleLong = isValidLong(rawvalue);
1212
                    }
1213
                    if (possibleDataType.possibleInt) {
1214
                        possibleDataType.possibleInt = isValidInteger(rawvalue);
1215
                    }
1216
                    if (possibleDataType.possibleDate) {
1217 41617 jjdelcerro
                        try {
1218 42775 jjdelcerro
                            toDate.coerce(rawvalue, locale);
1219
                            possibleDataType.possibleDate = true;
1220 41617 jjdelcerro
                        } catch (Exception ex) {
1221 42775 jjdelcerro
                            possibleDataType.possibleDate = false;
1222 41617 jjdelcerro
                        }
1223
                    }
1224 42775 jjdelcerro
                    if (possibleDataType.possibleURL) {
1225 41617 jjdelcerro
                        try {
1226 42775 jjdelcerro
                            new URL((String) rawvalue);
1227
                            possibleDataType.possibleURL = true;
1228 41617 jjdelcerro
                        } catch (Exception ex) {
1229 42775 jjdelcerro
                            possibleDataType.possibleURL = false;
1230 41617 jjdelcerro
                        }
1231
                    }
1232 42775 jjdelcerro
                    if (possibleDataType.possibleGeometry) {
1233 41617 jjdelcerro
                        try {
1234 42775 jjdelcerro
                            toGeom.coerce((String) rawvalue);
1235
                            possibleDataType.possibleGeometry = true;
1236 41617 jjdelcerro
                        } catch (Exception ex) {
1237 42775 jjdelcerro
                            possibleDataType.possibleGeometry = false;
1238 41617 jjdelcerro
                        }
1239
                    }
1240
                }
1241
                row = reader.read();
1242
            }
1243 42775 jjdelcerro
            int n = 0;
1244
            types = new int[possibleDataTypes.size()];
1245
            for (PossibleDataType possibleDataType : possibleDataTypes) {
1246
                if (possibleDataType.possibleInt) {
1247
                    types[n++] = DataTypes.INT;
1248
                    continue;
1249
                }
1250
                if (possibleDataType.possibleLong) {
1251
                    types[n++] = DataTypes.LONG;
1252
                    continue;
1253
                }
1254
                if (possibleDataType.possibleFloat) {
1255
                    // Forzamos los float a double para evitar perder precision
1256
                    types[n++] = DataTypes.DOUBLE;
1257
                    continue;
1258
                }
1259
                if (possibleDataType.possibleDouble) {
1260
                    types[n++] = DataTypes.DOUBLE;
1261
                    continue;
1262
                }
1263
                if (possibleDataType.possibleURL) {
1264
                    types[n++] = DataTypes.URL;
1265
                    continue;
1266
                }
1267
                if (possibleDataType.possibleDate) {
1268
                    types[n++] = DataTypes.DATE;
1269
                    continue;
1270
                }
1271
                if (possibleDataType.possibleGeometry) {
1272
                    types[n++] = DataTypes.GEOMETRY;
1273
                    continue;
1274
                }
1275
                types[n++] = DataTypes.STRING;
1276
            }
1277
        } catch (Exception ex) {
1278 41643 jjdelcerro
            int lineno = 0;
1279 42775 jjdelcerro
            if (reader != null) {
1280 41643 jjdelcerro
                lineno = reader.getLine();
1281
            }
1282 42775 jjdelcerro
            throw new RuntimeException("Problems reading file '" + getFullFileName() + "' near line " + lineno + ".", ex);
1283 41643 jjdelcerro
1284 41617 jjdelcerro
        } finally {
1285 42775 jjdelcerro
            IOUtils.closeQuietly(reader);
1286
            IOUtils.closeQuietly(in);
1287
        }
1288
        return types;
1289
    }
1290
1291
    private boolean isValidLong(String s) {
1292
        if (s == null) {
1293
            return true;
1294
        }
1295
        s = s.trim().toLowerCase();
1296
        if (s.isEmpty()) {
1297
            return true;
1298
        }
1299
        try {
1300
            if (s.startsWith("0x")) {
1301
                Long.valueOf(s.substring(2), 16);
1302
            } else {
1303
                Long.valueOf(s);
1304 41617 jjdelcerro
            }
1305 42775 jjdelcerro
            return true;
1306
        } catch (Exception ex) {
1307
            return false;
1308
        }
1309
    }
1310 41617 jjdelcerro
1311 42775 jjdelcerro
    private boolean isValidInteger(String s) {
1312
        if (s == null) {
1313
            return true;
1314 41617 jjdelcerro
        }
1315 42775 jjdelcerro
        s = s.trim().toLowerCase();
1316
        if (s.isEmpty()) {
1317
            return true;
1318
        }
1319
        try {
1320
            if (s.startsWith("0x")) {
1321
                Integer.valueOf(s.substring(2), 16);
1322
            } else {
1323
                Integer.valueOf(s);
1324 41617 jjdelcerro
            }
1325 42775 jjdelcerro
            return true;
1326
        } catch (Exception ex) {
1327
            return false;
1328 41617 jjdelcerro
        }
1329
    }
1330
1331 40846 jjdelcerro
}