Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.file / org.gvsig.fmap.dal.file.lib / src / main / java / org / gvsig / fmap / dal / feature / spi / simpleprovider / SimpleSequentialReaderStoreProvider.java @ 44259

History | View | Annotate | Download (42.1 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA 02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.fmap.dal.feature.spi.simpleprovider;
25

    
26
import java.io.File;
27
import java.io.IOException;
28
import java.util.ArrayList;
29
import java.util.HashMap;
30
import java.util.Iterator;
31
import java.util.List;
32
import java.util.Locale;
33
import java.util.Map;
34

    
35
import org.apache.commons.lang3.StringUtils;
36
import org.cresques.cts.IProjection;
37
import org.gvsig.fmap.dal.DALLocator;
38
import org.gvsig.fmap.dal.DataManager;
39
import org.gvsig.fmap.dal.DataServerExplorer;
40
import org.gvsig.fmap.dal.DataStore;
41
import org.gvsig.fmap.dal.DataStoreNotification;
42
import org.gvsig.fmap.dal.DataTypes;
43
import org.gvsig.fmap.dal.FileHelper;
44
import org.gvsig.fmap.dal.exception.DataException;
45
import org.gvsig.fmap.dal.exception.InitializeException;
46
import org.gvsig.fmap.dal.exception.OpenException;
47
import org.gvsig.fmap.dal.exception.ReadException;
48
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
49
import org.gvsig.fmap.dal.feature.EditableFeature;
50
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
51
import org.gvsig.fmap.dal.feature.EditableFeatureType;
52
import org.gvsig.fmap.dal.feature.Feature;
53
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
54
import org.gvsig.fmap.dal.feature.FeatureAttributeEmulator;
55
import org.gvsig.fmap.dal.feature.FeatureStore;
56
import org.gvsig.fmap.dal.feature.FeatureType;
57
import org.gvsig.fmap.dal.feature.exception.PerformEditingException;
58
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
59
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProviderServices;
60
import org.gvsig.fmap.dal.feature.spi.memory.AbstractMemoryStoreProvider;
61
import org.gvsig.fmap.dal.resource.file.FileResource;
62
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
63
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
64
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorer;
65
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorerParameters;
66
import org.gvsig.fmap.dal.spi.DALSPILocator;
67
import org.gvsig.fmap.dal.spi.DataManagerProviderServices;
68
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
69
import org.gvsig.fmap.geom.Geometry;
70
import org.gvsig.fmap.geom.GeometryLocator;
71
import org.gvsig.fmap.geom.GeometryManager;
72
import org.gvsig.fmap.geom.GeometryUtils;
73
import org.gvsig.fmap.geom.aggregate.MultiPoint;
74
import org.gvsig.fmap.geom.primitive.Envelope;
75
import org.gvsig.fmap.geom.primitive.Point;
76
import org.gvsig.fmap.geom.type.GeometryType;
77
import org.gvsig.timesupport.Interval;
78
import org.gvsig.tools.ToolsLocator;
79
import org.gvsig.tools.dataTypes.CoercionException;
80
import org.gvsig.tools.dataTypes.DataTypesManager;
81
import org.gvsig.tools.dataTypes.DataTypesManager.Coercion;
82
import org.gvsig.tools.dataTypes.DataTypesManager.CoercionWithLocale;
83
import org.gvsig.tools.dynobject.Tags;
84
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
85
import org.gvsig.tools.exception.BaseException;
86
import org.gvsig.tools.task.SimpleTaskStatus;
87
import org.gvsig.tools.task.TaskStatusManager;
88
import org.gvsig.tools.util.UnmodifiableBasicMap;
89
import org.gvsig.tools.util.UnmodifiableBasicMapToMapAdapter;
90
import org.gvsig.tools.util.UnmodifiableBasicSet;
91
import org.gvsig.tools.visitor.VisitCanceledException;
92
import org.gvsig.tools.visitor.Visitor;
93
import org.slf4j.Logger;
94
import org.slf4j.LoggerFactory;
95

    
96
@SuppressWarnings("UseSpecificCatch")
97
public class SimpleSequentialReaderStoreProvider extends AbstractMemoryStoreProvider implements
98
        ResourceConsumer {
99

    
100
    private static final Logger LOGGER = LoggerFactory.getLogger(SimpleSequentialReaderStoreProvider.class);
101

    
102
    private class ReaderData {
103
        private FeatureType defaultFeatureType;
104
        private List<FeatureType> featureTypes;
105
        private final List<FeatureProvider> features;
106
        private boolean needCalculateEnvelope;
107
        private String name;
108
        private long OIDcounter;
109
        private DataStore store;
110

    
111
        public ReaderData() {
112
            this.needCalculateEnvelope = false;
113
            this.features = new ArrayList<>();
114
            this.OIDcounter = 0;
115
            this.store = null;
116
        }
117
        
118
        public void addFeatureProvider(FeatureProvider feature) {
119
                feature.setOID(this.OIDcounter++);
120
                this.features.add(feature);
121
        }
122
        
123
        public void setFeatureTypes(List<FeatureType> featureTypes, FeatureType defaultFeatureType) {
124
            this.featureTypes = featureTypes;
125
            this.defaultFeatureType = defaultFeatureType;
126
        }
127
        
128
        public void setNeedCalculateEnvelope(boolean needCalculateEnvelope) {
129
            this.needCalculateEnvelope = needCalculateEnvelope;
130
        }
131
        
132
        public boolean getNeedCalculateEnvelope() {
133
            return this.needCalculateEnvelope;
134
        }
135

    
136
        public String getName() {
137
            return name;
138
        }
139

    
140
        public void setName(String name) {
141
            this.name = name;
142
        }
143

    
144
        public List<FeatureType> getFeatureTypes() {
145
            return this.featureTypes;
146
        }
147

    
148
        public FeatureType getDefaultFeatureType() {
149
            return this.defaultFeatureType;
150
        }
151
        
152
        public List<FeatureProvider> getFeatures() {
153
            return this.features;
154
        }
155
        
156
        public DataStore getStore() throws InitializeException {
157
            if( this.store == null ) {
158
                SimpleSequentialReaderStoreProvider provider = new SimpleSequentialReaderStoreProvider(
159
                        readerFactory,
160
                        getParameters(),
161
                        null,
162
                        childrenData,
163
                        this
164
                );
165
                DataManagerProviderServices manager = DALSPILocator.getDataManagerProviderServices();
166
                this.store = manager.openStore(
167
                        getParameters(), 
168
                        provider
169
                );
170
                provider.setStoreServices((FeatureStoreProviderServices) this.store);
171
                provider.name = this.name;
172
            }
173
            return this.store;
174
        }
175
    }
176
    
177
    class Children implements UnmodifiableBasicMap<String, DataStore> {
178
        // Con esta clase se pospone la creacion de los stores hasta que se 
179
        // pide cada uno de ellos, y no cuando se pide el Map de estos, ya
180
        // que el map se puede pedir solo para saber si hay o cuantos hay.
181

    
182
        @Override
183
        public DataStore get(String key) {
184
            for (ReaderData child : childrenData) {
185
                if( StringUtils.equalsIgnoreCase(child.getName(), key) ) {
186
                    try {
187
                        return child.getStore();
188
                    } catch (Exception ex) {
189
                        throw new RuntimeException(ex);
190
                    }
191
                }
192
            }
193
            return null;
194
        }
195

    
196
        @Override
197
        public boolean isEmpty() {
198
            return childrenData.isEmpty();
199
        }
200

    
201
        @Override
202
        public boolean containsKey(String key) {
203
            for (ReaderData child : childrenData) {
204
                if( StringUtils.equalsIgnoreCase(child.getName(), key) ) {
205
                    return true;
206
                }
207
            }
208
            return false;
209
        }
210

    
211
        @Override
212
        public Map<String, DataStore> toMap() {
213
            return new UnmodifiableBasicMapToMapAdapter<>(this);
214
        }
215

    
216
        @Override
217
        public int size() {
218
            return childrenData.size();
219
        }
220

    
221
        @Override
222
        public UnmodifiableBasicSet<String> keySet() {
223
            return new UnmodifiableBasicSet<String>() {
224

    
225
                @Override
226
                public boolean isEmpty() {
227
                    return childrenData.isEmpty();
228
                }
229

    
230
                @Override
231
                public int size() {
232
                    return childrenData.size();
233
                }
234

    
235
                @Override
236
                public Iterator<String> iterator() {
237
                    final Iterator<ReaderData> it = childrenData.iterator();
238
                    return new Iterator<String>() {
239
                        @Override
240
                        public boolean hasNext() {
241
                            return it.hasNext();
242
                        }
243

    
244
                        @Override
245
                        public String next() {
246
                            ReaderData theReaderData = it.next();
247
                            return theReaderData.getName();
248
                        }
249
                    };
250
                }
251
            };
252
        }
253

    
254
        @Override
255
        public Iterator<DataStore> iterator() {
256
            final Iterator<String> it = this.keySet().iterator();
257
            return new Iterator<DataStore>() {
258
                @Override
259
                public boolean hasNext() {
260
                    return it.hasNext();
261
                }
262

    
263
                @Override
264
                public DataStore next() {
265
                    String name = it.next();
266
                    return get(name);
267
                }
268
            };
269
        }
270
        
271
    }
272

    
273
    private final ResourceProvider resource;
274

    
275
    private Envelope envelope;
276
    private boolean need_calculate_envelope = false;
277
    private final SimpleTaskStatus taskStatus;
278
    private String name = "";
279
    private final SimpleSequentialReaderFactory readerFactory;
280
    private List<ReaderData> childrenData;
281
    private ReaderData readerData;
282

    
283
    public SimpleSequentialReaderStoreProvider(
284
            SimpleSequentialReaderFactory readerFactory,
285
            SimpleSequentialReaderStoreParameters parameters,
286
            DataStoreProviderServices storeServices
287
        ) throws InitializeException {
288
        this(readerFactory, parameters, storeServices, new ArrayList<ReaderData>(), null);
289
    }
290
    
291
    private SimpleSequentialReaderStoreProvider(
292
            SimpleSequentialReaderFactory readerFactory,
293
            SimpleSequentialReaderStoreParameters parameters,
294
            DataStoreProviderServices storeServices,
295
            List<ReaderData> childrenData,
296
            ReaderData readerData
297
            
298
        ) throws InitializeException {
299
        super(
300
                parameters,
301
                storeServices,
302
                FileHelper.newMetadataContainer(readerFactory.getName())
303
        );
304
        this.childrenData = childrenData;
305
        this.readerData = readerData;
306
        this.readerFactory = readerFactory;
307
        TaskStatusManager manager = ToolsLocator.getTaskStatusManager();
308
        this.taskStatus = manager.createDefaultSimpleTaskStatus(readerFactory.getName());
309

    
310
        File file = getParameters().getFile();
311
        resource = this.createResource(
312
                FileResource.NAME,
313
                new Object[]{file.getAbsolutePath()}
314
        );
315

    
316
        resource.addConsumer(this);
317
        if( this.readerData!=null ) {
318
            this.name = this.readerData.getName();            
319
        }
320
        if( storeServices != null ) {
321
            initializeFeatureTypes();
322
        }
323
    }
324

    
325
    private void setStoreServices(FeatureStoreProviderServices storeServices) throws InitializeException {
326
        this.store = storeServices;
327
        initializeFeatureTypes();
328
    }
329
    
330
    @Override
331
    public SimpleSequentialReaderStoreParameters getParameters() {
332
        return (SimpleSequentialReaderStoreParameters) super.getParameters();
333
    }
334

    
335
    @Override
336
    public String getProviderName() {
337
        if( this.readerFactory==null ) {
338
            return "unknown";
339
        }
340
        return this.readerFactory.getName();
341
    }
342

    
343
    @Override
344
    public boolean allowWrite() {
345
        return false;
346
    }
347

    
348
    private String getFullFileName() {
349
        // Usar solo para mostrar mensajes en el logger.
350
        String s;
351
        try {
352
            s = getParameters().getFile().getAbsolutePath();
353
        } catch (Exception e2) {
354
            s = "(unknow)";
355
        }
356
        return s;
357
    }
358

    
359
    @Override
360
    public void open() throws OpenException {
361
        if ( this.data != null ) {
362
            return;
363
        }
364
        this.data = new ArrayList<>();
365
        resource.setData(new HashMap());
366
        try {
367
            loadFeatures();
368
        } catch (RuntimeException e) {
369
            LOGGER.warn("Can't load features from '"+getProviderName()+"' file '" + getFullFileName() + "'.", e);
370
            throw e;
371
        } catch (Exception e) {
372
            LOGGER.warn("Can't load features from '"+getProviderName()+"' file '" + getFullFileName() + "'.", e);
373
            throw new RuntimeException(e);
374
        }
375
    }
376

    
377
    @Override
378
    public DataServerExplorer getExplorer() throws ReadException {
379
        DataManager manager = DALLocator.getDataManager();
380
        FilesystemServerExplorerParameters params;
381
        try {
382
            params = (FilesystemServerExplorerParameters) manager
383
                    .createServerExplorerParameters(FilesystemServerExplorer.NAME);
384
            params.setRoot(this.getParameters().getFile().getParent());
385
            return manager.openServerExplorer(FilesystemServerExplorer.NAME, params);
386
        } catch (DataException | ValidateDataParametersException e) {
387
            throw new ReadException(this.getProviderName(), e);
388
        }
389

    
390
    }
391

    
392
    @Override
393
    public void performChanges(Iterator deleteds, Iterator inserteds, Iterator updateds, Iterator originalFeatureTypesUpdated) throws PerformEditingException {
394
        throw new UnsupportedOperationException();
395
    }
396

    
397
    @Override
398
    public boolean closeResourceRequested(ResourceProvider resource) {
399
        return true;
400
    }
401

    
402
    @Override
403
    public int getOIDType() {
404
        return DataTypes.LONG;
405
    }
406

    
407
    @Override
408
    public boolean supportsAppendMode() {
409
        return false;
410
    }
411

    
412
    @Override
413
    public void append(FeatureProvider featureProvider) {
414
        throw new UnsupportedOperationException();
415
    }
416

    
417
    @Override
418
    public void beginAppend() {
419
        throw new UnsupportedOperationException();
420
    }
421

    
422
    @Override
423
    public void endAppend() {
424
        throw new UnsupportedOperationException();
425
    }
426

    
427
    @Override
428
    public Object createNewOID() {
429
        throw new UnsupportedOperationException();
430
    }
431

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

    
440
    @Override
441
    public Envelope getEnvelope() throws DataException {
442
        this.open();
443
        if ( this.envelope != null ) {
444
            return this.envelope;
445
        }
446
        if ( !this.need_calculate_envelope ) {
447
            return null;
448
        }
449
        FeatureStore fs = this.getFeatureStore();
450
        FeatureType ft = fs.getDefaultFeatureType();
451
        FeatureAttributeDescriptor fad = ft.getAttributeDescriptor(ft.getDefaultGeometryAttributeIndex());
452

    
453
        try {
454
            this.envelope = GeometryLocator.getGeometryManager().createEnvelope(fad.getGeomType().getSubType());
455
            fs.accept(new Visitor() {
456
                @Override
457
                public void visit(Object obj) throws VisitCanceledException, BaseException {
458
                    Feature f = (Feature) obj;
459
                    Geometry geom = f.getDefaultGeometry();
460
                    if ( geom != null ) {
461
                        envelope.add(geom.getEnvelope());
462
                    }
463
                }
464
            });
465
        } catch (BaseException e) {
466
            LOGGER.warn("Can't calculate the envelope of '"+getProviderName()+"' file '" + this.getFullName() + "'.", e);
467
            this.envelope = null;
468
        }
469

    
470
        this.need_calculate_envelope = false;
471
        return this.envelope;
472
    }
473

    
474
    @Override
475
    public Object getDynValue(String name) throws DynFieldNotFoundException {
476
        if ( DataStore.METADATA_ENVELOPE.equalsIgnoreCase(name) ) {
477
            try {
478
                return this.getEnvelope();
479
            } catch (DataException e) {
480
                return null;
481
            }
482
        } else {
483
            if ( DataStore.METADATA_CRS.equalsIgnoreCase(name) ) {
484
                IProjection pro = this.getParameters().getCRS();
485
                if ( pro != null ) {
486
                    return pro;
487
                }
488
                FeatureType type;
489
                try {
490
                    type = this.getStoreServices().getDefaultFeatureType();
491
                    pro = type.getDefaultSRS();
492
                    if( pro!=null ) {
493
                        return pro;
494
                    }
495
                } catch (DataException ex) {
496
                }
497
            }
498
        }
499
        return super.getDynValue(name);
500
    }
501

    
502
    @Override
503
    public void resourceChanged(ResourceProvider resource) {
504
        this.getStoreServices().notifyChange(
505
                DataStoreNotification.RESOURCE_CHANGED,
506
                resource);
507
    }
508

    
509
    @Override
510
    public Object getSourceId() {
511
        return this.getParameters().getFile();
512
    }
513

    
514
    @Override
515
    public String getName() {
516
        return this.name;
517
    }
518

    
519
    @Override
520
    public String getFullName() {
521
        return this.getParameters().getFile().getAbsolutePath();
522
    }
523

    
524
    @Override
525
    public ResourceProvider getResource() {
526
        return resource;
527
    }
528

    
529
    private String[] split(String value, String separators) {
530
        int firstSeparatorPosition = 1000000;
531
        Character sep = null;
532
        for (char ch : separators.toCharArray()) {
533
            int pos = value.indexOf(ch);
534
            if( pos>0 && pos<firstSeparatorPosition ) {
535
                sep = ch;
536
                firstSeparatorPosition = pos;
537
            }
538
        }
539
        if( sep == null ) {
540
            return new String[] { value };
541
        }
542
        return value.split("["+sep+"]");
543
    }
544
    
545
    private class FieldTypeParser {
546

    
547
        public String name = null;
548
        public int type = DataTypes.STRING;
549
        public int size = 0;
550
        public int geomType = Geometry.TYPES.GEOMETRY;
551
        public int geomSubtype = Geometry.SUBTYPES.GEOM2D;
552
        public Map<String,String> tags = new HashMap<>();
553
        public Map<String,String> assignments = new HashMap<>();
554

    
555
        private String typename = "string";
556

    
557
        FieldTypeParser() {
558
        }
559

    
560
        private int getType(String value) {
561
            DataTypesManager dataTypesManager = ToolsLocator.getDataTypesManager();
562
            return dataTypesManager.getType(typename);
563
        }
564

    
565
        @SuppressWarnings("UseSpecificCatch")
566
        public boolean parse(String value) {
567
            String[] args;
568
            if ( value.contains("__") ) {
569
                args = value.split("__");
570
            } else {
571
                args = split(value, ":/#@!;-");
572
                if( args.length == 1 ) {
573
                    this.name = value;
574
                    return true;
575
                }
576
            }                        
577
            int n = 0;
578
            this.name = args[n++];
579
            if( n >= args.length ) {
580
                return true;
581
            }
582
            this.typename = args[n++];
583
            this.type = this.getType(this.typename);
584
            if ( this.type == DataTypes.INVALID ) {
585
                this.geomType = GeometryUtils.getGeometryType(this.typename);
586
                if( this.geomType==Geometry.TYPES.UNKNOWN )  {
587
                    this.type = DataTypes.STRING;
588
                    LOGGER.info("Type '" + this.typename + "' not valid for attribute '" + value + "' in '"+getProviderName()+"' file '" + getFullFileName() + "'.");
589
                } else {
590
                    this.typename = "GEOMETRY";
591
                    this.type = DataTypes.GEOMETRY;
592
                }
593
            }
594
            switch(this.type) {
595
                case DataTypes.STRING:
596
                    this.size = 50;
597
                    break;
598
                case DataTypes.INT:
599
                    this.size = 10;
600
                    break;
601
                case DataTypes.LONG:
602
                    this.size = 20;
603
                    break;
604
                case DataTypes.FLOAT:
605
                    this.size = 10;
606
                    break;
607
                case DataTypes.DOUBLE:
608
                    this.size = 20;
609
                    break;
610
                default:
611
                    this.size = 0;
612
            }
613
            while (n < args.length) {
614
                String option = args[n++].toLowerCase();
615
                switch (option) {
616
                    case "size":
617
                        try {
618
                            this.size = Integer.parseInt(args[n++]);
619
                        } catch (Exception ex) {
620
                            LOGGER.warn("Ignore incorrect field size for field " + value + " in '"+getProviderName()+"' file '" + getFullFileName() + "'.", ex);
621
                        }
622
                        break;
623
                    case "tag": {
624
                            String x = args[n++];
625
                            int pos = x.indexOf("=");
626
                            if( pos < 0 ) {
627
                                this.tags.put(x, null);
628
                            } else {
629
                                this.tags.put( 
630
                                        StringUtils.substring(x, 0, pos),
631
                                        StringUtils.substring(x, pos+1)
632
                                );
633
                            }
634
                            break;
635
                        }
636
                    case "set": {
637
                            String x = args[n++];
638
                            int pos = x.indexOf("=");
639
                            if( pos < 0 ) {
640
                                this.assignments.put(x, null);
641
                            } else {
642
                                this.assignments.put( 
643
                                        StringUtils.substring(x, 0, pos),
644
                                        StringUtils.substring(x, pos+1)
645
                                );
646
                            }
647
                            break;
648
                        }
649
                    default:
650
                        LOGGER.warn("Illegal argumente '"+option+"' for field '"+this.name+"' in '"+getProviderName()+"' file '" + getFullFileName() + "' ("+value+").");
651
                }
652
            }
653
            return true;
654
        }
655

    
656
    }
657

    
658
    private EditableFeatureType getFeatureType(List<String> headers, int automaticTypes[]) {
659
        EditableFeatureType fType = getStoreServices().createFeatureType(this.getName());
660
        fType.setHasOID(true);
661
//        DataTypesManager dataTypesManager = ToolsLocator.getDataTypesManager();
662

    
663
        FieldTypeParser[] fieldTypes = new FieldTypeParser[headers.size()];
664
        //
665
        // Calculamos cuales pueden ser los tipos de datos
666
        //
667
        for ( int i = 0; i < fieldTypes.length; i++ ) {
668
            fieldTypes[i] = new FieldTypeParser();
669
        }
670

    
671
        // Asuminos los tipos pasados por parametro, que se supone
672
        // son los detectados automaticamente.
673
        if ( automaticTypes != null ) {
674
            for ( int i = 0; i < fieldTypes.length && i < automaticTypes.length; i++ ) {
675
                fieldTypes[i].type = automaticTypes[i];
676
            }
677
        }
678
        // Luego probamos con lo que diga las cabezeras, sobreescribiendo
679
        // los tipos anteriores en caso de definirse en la cabezara.
680
        for ( int i = 0; i < fieldTypes.length; i++ ) {
681
            fieldTypes[i].parse(headers.get(i));
682
        }
683

    
684
        // Y por ultimo hacemos caso a lo que se haya especificado en los parametros
685
        // de apertura del reader, teniendo esto prioridad sobre todo.
686
        int[] param_types = this.getParameters().getFieldTypes();
687
        if ( param_types != null ) {
688
            for ( int i = 0; i < fieldTypes.length && i < param_types.length; i++ ) {
689
                fieldTypes[i].type = param_types[i];
690
            }
691
        }
692

    
693
        int[] param_sizes = this.getParameters().getFieldSizes();
694
        if ( param_sizes != null ) {
695
            for ( int i = 0; i < param_sizes.length; i++ ) {
696
                if ( param_sizes[i] > 0 ) {
697
                    fieldTypes[i].size = param_sizes[i];
698
                }
699
            }
700
        }
701
        //
702
        // Una vez ya sabemos los tipos de datos rellenamos el feature-type
703
        //
704
        DataTypesManager dataTypesManager = ToolsLocator.getDataTypesManager();
705
        for (FieldTypeParser fieldType : fieldTypes) {
706
            EditableFeatureAttributeDescriptor fad = fType.add(fieldType.name, fieldType.type);
707
            fad.setSize(fieldType.size);
708
            if (fieldType.type == DataTypes.GEOMETRY ) {
709
                fad.setGeometryType(fieldType.geomType, fieldType.geomSubtype);
710
                if( fType.getDefaultGeometryAttributeName() == null ) {
711
                    fType.setDefaultGeometryAttributeName(fieldType.name);
712
                }
713
            }
714
            for (Map.Entry<String, String> entry : fieldType.assignments.entrySet()) {
715
                try {
716
                    switch(entry.getKey().toLowerCase()) {
717
                        case "hidden":
718
                            fad.setHidden((boolean) dataTypesManager.coerce(DataTypes.BOOLEAN, entry.getValue()));
719
                            break;
720
                        case "allownull":
721
                            fad.setAllowNull((boolean) dataTypesManager.coerce(DataTypes.BOOLEAN, entry.getValue()));
722
                            break;
723
                        case "isautomatic":
724
                        case "automatic":
725
                            fad.setIsAutomatic((boolean) dataTypesManager.coerce(DataTypes.BOOLEAN, entry.getValue()));
726
                            break;
727
                        case "time":
728
                        case "istime":
729
                            fad.setIsTime((boolean) dataTypesManager.coerce(DataTypes.BOOLEAN, entry.getValue()));
730
                            break;
731
                        case "profile":
732
                            fad.setDataProfileName((String) dataTypesManager.coerce(DataTypes.STRING, entry.getValue()));
733
                            break;
734
                        case "group":
735
                            fad.setGroup((String) dataTypesManager.coerce(DataTypes.STRING, entry.getValue()));
736
                            break;
737
                        case "description":
738
                            fad.setDescription((String) dataTypesManager.coerce(DataTypes.STRING, entry.getValue()));
739
                            break;
740
                        case "label":
741
                            fad.setLabel((String) dataTypesManager.coerce(DataTypes.STRING, entry.getValue()));
742
                            break;
743
                        case "expression":
744
                            // Los campos calculados los procesamos en una segunda
745
                            // pasada, cuando ya estan definidos el resto de los campos
746
                            // ya que pueden requerir campos que aun no se han definido.
747
                            break;
748
                        case "size":
749
                            fad.setSize((int) dataTypesManager.coerce(DataTypes.INT, entry.getValue()));
750
                            break;
751
                        case "precision":
752
                            fad.setPrecision((int) dataTypesManager.coerce(DataTypes.INT, entry.getValue()));
753
                            break;
754
                        case "order":
755
                            fad.setOrder((int) dataTypesManager.coerce(DataTypes.INT, entry.getValue()));
756
                            break;
757
                        case "interval":
758
                            fad.setInterval((Interval) dataTypesManager.coerce(DataTypes.INTERVAL, entry.getValue()));
759
                            break;
760
                        case "geomtype":
761
                        case "geometrytype":
762
                            fad.setGeometryType(entry.getValue());
763
                            break;
764
                        case "srs":
765
                            fad.setSRS(entry.getValue());
766
                            break;
767
                    }
768
                } catch (Exception ex) {
769
                    LOGGER.warn("Can't set property '"+entry.getKey()+"' of '"+fad.getName()+"'.", ex);
770
                }
771
            }
772
            Tags tags = fad.getTags();
773
            for (Map.Entry<String, String> entry : fieldType.tags.entrySet()) {
774
                tags.set(entry.getKey(), entry.getValue());
775
            }
776
        }
777
        // Processamos ahora los campos calculados
778
        for (FieldTypeParser fieldType : fieldTypes) {
779
            EditableFeatureAttributeDescriptor fad = fType.getEditableAttributeDescriptor(fieldType.name);
780
            for (Map.Entry<String, String> entry : fieldType.assignments.entrySet()) {
781
                try {
782
                    switch(entry.getKey().toLowerCase()) {
783
                        case "expression":
784
                            fad.setFeatureAttributeEmulator((String) dataTypesManager.coerce(DataTypes.STRING, entry.getValue()));
785
                            break;
786
                    }
787
                } catch (Exception ex) {
788
                    LOGGER.warn("Can't set property '"+entry.getKey()+"' in '"+fad.getName()+"' of '"+getFullFileName()+"'.", ex);
789
                }
790
            }
791
        }
792

    
793
        String[] pointDimensionNames = this.getParameters().getPointDimensionNames();
794
        if ( pointDimensionNames != null ) {
795
            PointAttributeEmulator emulator = new PointAttributeEmulator(pointDimensionNames);
796
            EditableFeatureAttributeDescriptor attr = fType.add("the_geom", DataTypes.GEOMETRY, emulator);
797
            GeometryManager geommgr = GeometryLocator.getGeometryManager();
798
            GeometryType gt;
799
            try {
800
                if ( emulator.fieldNames != null && emulator.fieldNames.length <= 2 ) {
801
                        gt = geommgr.getGeometryType(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D);
802
                } else {
803
                        gt = geommgr.getGeometryType(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D);
804
                }
805
                attr.setGeometryType(gt);
806
            } catch (Exception e) {
807
                LOGGER.warn("Can't set geometry type for the calculated field in '"+getProviderName()+"' file '" + getFullFileName() + "'.", e);
808
            }
809
        }
810
        return fType;
811
    }
812

    
813
    class PointAttributeEmulator implements FeatureAttributeEmulator {
814

    
815
        private static final int XNAME = 0;
816
        private static final int YNAME = 1;
817
        private static final int ZNAME = 2;
818

    
819
        private final GeometryManager geommgr;
820
        private final String[] fieldNames;
821
        private final Coercion toDouble;
822
        private int errorcount = 0;
823

    
824
        public PointAttributeEmulator(String[] pointDimensionNames) {
825
            if ( pointDimensionNames.length > 2 ) {
826
                this.fieldNames = new String[3];
827
                this.fieldNames[ZNAME] = pointDimensionNames[2];
828
            } else {
829
                this.fieldNames = new String[2];
830
            }
831
            this.fieldNames[XNAME] = pointDimensionNames[0];
832
            this.fieldNames[YNAME] = pointDimensionNames[1];
833
            this.geommgr = GeometryLocator.getGeometryManager();
834
            DataTypesManager datatypeManager = ToolsLocator.getDataTypesManager();
835

    
836
            this.toDouble = datatypeManager.getCoercion(DataTypes.DOUBLE);
837
        }
838

    
839
        @Override
840
        @SuppressWarnings("UseSpecificCatch")
841
        public Object get(Feature feature) {
842
            try {
843
                Object valueX = feature.get(this.fieldNames[XNAME]);
844
                valueX = toDouble.coerce(valueX);
845
                if ( valueX == null ) {
846
                    return null;
847
                }
848
                Object valueY = feature.get(this.fieldNames[YNAME]);
849
                valueY = toDouble.coerce(valueY);
850
                if ( valueY == null ) {
851
                    return null;
852
                }
853
                Object valueZ = null;
854
                if ( this.fieldNames.length > 2 ) {
855
                    valueZ = toDouble.coerce(feature.get(this.fieldNames[ZNAME]));
856
                    if ( valueZ == null ) {
857
                        return null;
858
                    }
859
                }
860

    
861
                double x = ((Double) valueX);
862
                double y = ((Double) valueY);
863
                Point point;
864
                if ( this.fieldNames.length > 2 ) {
865
                    point = geommgr.createPoint(x, y, Geometry.SUBTYPES.GEOM3D);
866
                    double z = ((Double) valueZ);
867
                    point.setCoordinateAt(2, z);
868
                } else {
869
                    point = geommgr.createPoint(x, y, Geometry.SUBTYPES.GEOM2D);
870
                }
871
                return point;
872
            } catch (Exception ex) {
873
                if ( ++errorcount < 5 ) {
874
                    LOGGER.warn("[" + errorcount + "] Can't create point from '"+getProviderName()+"' file."+
875
                            "XNAME='" + this.fieldNames[XNAME] + 
876
                            "', YNAME='" + this.fieldNames[YNAME] + 
877
                            "', ZNAME='" + ((this.fieldNames.length > 2)? this.fieldNames[ZNAME]: "(2D)") +
878
                            "' feature=" + feature.toString(), ex);
879
                }
880
                return null;
881
            }
882
        }
883

    
884
        @Override
885
        public void set(EditableFeature feature, Object value) {
886
            if ( value == null ) {
887
                return;
888
            }
889
            Point point;
890
            if ( value instanceof MultiPoint ) {
891
                point = (Point) ((MultiPoint) value).getPrimitiveAt(0);
892
            } else {
893
                point = (Point) value;
894
            }
895
            feature.set(this.fieldNames[XNAME], point.getX());
896
            feature.set(this.fieldNames[YNAME], point.getY());
897
            if ( this.fieldNames.length > 2 ) {
898
                feature.set(this.fieldNames[ZNAME], point.getCoordinateAt(2));
899
            }
900
        }
901

    
902
        @Override
903
        public boolean allowSetting() {
904
            return true;
905
        }
906

    
907
        @Override
908
        public String[] getRequiredFieldNames() {
909
            return this.fieldNames;
910
        }
911

    
912
    }
913

    
914
    private void loadFeatures() throws IOException, DataException,
915
            CoercionException, CloneNotSupportedException {
916

    
917
        ReaderData theReaderData = this.readerData;
918
        if( theReaderData==null ) {
919
            theReaderData = new ReaderData();
920
            SimpleSequentialReader reader = this.readerFactory.createReader(this.getParameters());
921
            try {
922
                loadFeatures(reader, theReaderData);
923
                this.childrenData = new ArrayList<>();
924
                for(SimpleSequentialReader childReader : reader.getChildren() ) {
925
                    ReaderData childData = new ReaderData();
926
                    loadFeatures(childReader, childData);
927
                    this.childrenData.add(childData);
928
                }
929
                this.readerData = theReaderData;
930
            } finally {
931
                reader.close();
932
            }
933
        }
934
        this.name = theReaderData.getName();
935
        FeatureStoreProviderServices theStore = this.getStoreServices();
936
        theStore.setFeatureTypes(theReaderData.getFeatureTypes(), theReaderData.getDefaultFeatureType());
937
        this.need_calculate_envelope = theReaderData.getNeedCalculateEnvelope();
938
        this.data = theReaderData.getFeatures();
939

    
940
    }
941
    
942
    private void loadFeatures(SimpleSequentialReader reader, ReaderData readerData) throws IOException, DataException,
943
            CoercionException, CloneNotSupportedException {
944

    
945
        try {
946
            List<String> headers;
947

    
948
            readerData.setName(reader.getName());
949
            
950
            boolean ignore_errors = getParameters().getIgnoreErrors();
951

    
952
            headers = getParameters().getFieldNames();
953
            if ( headers == null ) {
954
                headers = reader.getFieldNames();
955
            }
956

    
957
            // Initialize the feature types
958
            EditableFeatureType edftype = this.getFeatureType(headers, automaticDetectionOfTypes(reader));
959

    
960
            edftype.setLabel(reader.getLabel());
961
            edftype.setDescription(reader.getDescription());
962
            Map<String, String> tagsReader = reader.getTags();
963
            if( tagsReader!=null ) {
964
                Tags tagsType = edftype.getTags();
965
                for (Map.Entry<String, String> tag : tagsReader.entrySet()) {
966
                    tagsType.set(tag.getKey(), tag.getValue());
967
                }
968
            }
969
            
970
            FeatureType ftype = edftype.getNotEditableCopy();
971
            List<FeatureType> ftypes = new ArrayList<>();
972
            ftypes.add(ftype);
973
            readerData.setFeatureTypes(ftypes, ftype);
974

    
975
            Coercion coercion[] = new Coercion[ftype.size()];
976
            int sizes[] = new int[ftype.size()];
977
            for ( int i = 0; i < ftype.size(); i++ ) {
978
                sizes[i] = -1;
979
                FeatureAttributeDescriptor ad = ftype.getAttributeDescriptor(i);
980
                coercion[i] = ad.getDataType().getCoercion();
981
                if ( ad.getDataType().getType() == DataTypes.STRING ) {
982
                    if ( ad.getSize() == 0 ) {
983
                        // Es un string y no tiene un size asignado.
984
                        // Lo ponemos a cero para calcularlo.
985
                        sizes[i] = 0;
986
                    }
987
                }
988
            }
989
           
990
            if ( ftype.getDefaultGeometryAttributeName() != null ) {
991
                readerData.setNeedCalculateEnvelope(true);
992
            }
993

    
994
            Locale locale = getParameters().getLocale();
995
            taskStatus.message("_loading");
996
            int count = 0;
997

    
998
            int count_errors = 0;
999
            
1000
            reader.rewind();
1001
            List<Object> row = reader.read();
1002

    
1003
            Object rawvalue;
1004
            while ( row != null ) {
1005
                taskStatus.setCurValue(++count);
1006
                FeatureProvider feature = this.createFeatureProvider(ftype);
1007
                for ( int i = 0; i < row.size(); i++ ) {
1008
                    try {
1009
                        if( ftype.get(i).isComputed() ) {
1010
                            continue;
1011
                        }
1012
                        rawvalue = row.get(i);
1013
                        if( rawvalue instanceof String && StringUtils.isBlank((String)rawvalue) ) {
1014
                            rawvalue = null;
1015
                        }
1016
                        Object value;
1017
                        if ( locale != null && coercion[i] instanceof CoercionWithLocale ) {
1018
                            value = ((CoercionWithLocale) (coercion[i])).coerce(rawvalue, locale);
1019
                        } else {
1020
                            value = coercion[i].coerce(rawvalue);
1021
                        }
1022
                        feature.set(i, value);
1023
                        if ( sizes[i] >= 0 && value != null ) {
1024
                            int x = ((String) value).length();
1025
                            if ( sizes[i] < x ) {
1026
                                sizes[i] = x;
1027
                            }
1028
                        }
1029
                    } catch (Exception ex) {
1030
                        if ( !ignore_errors ) {
1031
                            throw ex;
1032
                        }
1033
                        if ( count_errors++ < 10 ) {
1034
                            LOGGER.warn("Can't load value of attribute " + i+"/"+row.size()+"/"+ftype.size()+ " in row " + count + " in " +readerData.getName()+ ".", ex);
1035
                        }
1036
                        if ( count_errors == 10 ) {
1037
                            LOGGER.info("Too many errors, suppress messages.");
1038
                        }
1039
                    }
1040
                }
1041
                readerData.addFeatureProvider(feature);
1042
                row = reader.read();
1043
            }
1044
            for ( int i = 0; i < ftype.size(); i++ ) {
1045
                if ( sizes[i] > 0 ) {
1046
                    EditableFeatureAttributeDescriptor efad = ((EditableFeatureAttributeDescriptor) edftype.getAttributeDescriptor(i));
1047
                    if( efad.getSize()<sizes[i] ) {
1048
                        efad.setSize(sizes[i]);
1049
                    }
1050
                }
1051
            }
1052
            // Volvemos a asignar al store el featuretype, ya que puede
1053
            // haber cambiado.
1054
            ftype = edftype.getNotEditableCopy();
1055
            ftypes = new ArrayList<>();
1056
            ftypes.add(ftype);
1057
            readerData.setFeatureTypes(ftypes, ftype);
1058

    
1059
            taskStatus.terminate();
1060
        } catch (Exception ex) {
1061
            LOGGER.warn("Can't load features from '"+getProviderName()+"' file '" + getFullFileName() + "'.", ex);
1062
        }
1063
    }
1064
    
1065
    private int[] automaticDetectionOfTypes(SimpleSequentialReader reader) throws IOException {
1066
        boolean automatic_types_detection = getParameters().getAutomaticTypesDetection();
1067
        if ( !automatic_types_detection ) {
1068
            return null;
1069
        }
1070
        int[] types = null;
1071
        try {
1072
            reader.rewind();
1073
            List<String> fieldNames = reader.getFieldNames();
1074
            if ( fieldNames == null ) {
1075
                fieldNames = getParameters().getFieldNames();
1076
            }
1077

    
1078
            AutomaticDetectionOfTypes x = new AutomaticDetectionOfTypes(
1079
                    this.getFullFileName()
1080
            );
1081
            types = x.detect(
1082
                    fieldNames.size(), 
1083
                    reader, 
1084
                    false, 
1085
                    getParameters().getLocale()
1086
            );
1087
        } catch (Exception ex) {
1088
            throw new RuntimeException("Problems reading '"+getProviderName()+"' file '" + getFullFileName() + "'.", ex);
1089
        }
1090
        return types;
1091
    }
1092

    
1093
    @Override
1094
    public boolean hasDynValue(String name) {
1095
        if ( DataStore.METADATA_ENVELOPE.equalsIgnoreCase(name) ) {
1096
            return true;
1097
        } else if ( DataStore.METADATA_CRS.equalsIgnoreCase(name) ) {
1098
            return true;
1099
        }
1100
        return super.hasDynValue(name);
1101
    }
1102

    
1103
    @Override
1104
    public UnmodifiableBasicMap<String, DataStore> getChildren() {
1105
        return new Children();
1106
    }
1107

    
1108
}