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

History | View | Annotate | Download (42.7 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 String name = "";
278
    private final SimpleSequentialReaderFactory readerFactory;
279
    private List<ReaderData> childrenData;
280
    private ReaderData readerData;
281

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

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

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

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

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

    
340
    @Override
341
    public boolean allowWrite() {
342
        return false;
343
    }
344

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

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

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

    
387
    }
388

    
389
    @Override
390
    public void performChanges(Iterator deleteds, Iterator inserteds, Iterator updateds, Iterator originalFeatureTypesUpdated) throws PerformEditingException {
391
        throw new UnsupportedOperationException();
392
    }
393

    
394
    @Override
395
    public boolean closeResourceRequested(ResourceProvider resource) {
396
        return true;
397
    }
398

    
399
    @Override
400
    public int getOIDType() {
401
        return DataTypes.LONG;
402
    }
403

    
404
    @Override
405
    public boolean supportsAppendMode() {
406
        return false;
407
    }
408

    
409
    @Override
410
    public void append(FeatureProvider featureProvider) {
411
        throw new UnsupportedOperationException();
412
    }
413

    
414
    @Override
415
    public void beginAppend() {
416
        throw new UnsupportedOperationException();
417
    }
418

    
419
    @Override
420
    public void endAppend() {
421
        throw new UnsupportedOperationException();
422
    }
423

    
424
    @Override
425
    public Object createNewOID() {
426
        throw new UnsupportedOperationException();
427
    }
428

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

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

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

    
467
        this.need_calculate_envelope = false;
468
        return this.envelope;
469
    }
470

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

    
499
    @Override
500
    public void resourceChanged(ResourceProvider resource) {
501
        this.getStoreServices().notifyChange(
502
                DataStoreNotification.RESOURCE_CHANGED,
503
                resource);
504
    }
505

    
506
    @Override
507
    public Object getSourceId() {
508
        return this.getParameters().getFile();
509
    }
510

    
511
    @Override
512
    public String getName() {
513
        return this.name;
514
    }
515

    
516
    @Override
517
    public String getFullName() {
518
        return this.getParameters().getFile().getAbsolutePath();
519
    }
520

    
521
    @Override
522
    public ResourceProvider getResource() {
523
        return resource;
524
    }
525

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

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

    
552
        private String typename = "string";
553

    
554
        FieldTypeParser() {
555
        }
556

    
557
        private int getType(String value) {
558
            DataTypesManager dataTypesManager = ToolsLocator.getDataTypesManager();
559
            return dataTypesManager.getType(typename);
560
        }
561

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

    
653
    }
654

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

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

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

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

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

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

    
816
    class PointAttributeEmulator implements FeatureAttributeEmulator {
817

    
818
        private static final int XNAME = 0;
819
        private static final int YNAME = 1;
820
        private static final int ZNAME = 2;
821

    
822
        private final GeometryManager geommgr;
823
        private final String[] fieldNames;
824
        private final Coercion toDouble;
825
        private int errorcount = 0;
826

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

    
839
            this.toDouble = datatypeManager.getCoercion(DataTypes.DOUBLE);
840
        }
841

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

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

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

    
905
        @Override
906
        public boolean allowSetting() {
907
            return true;
908
        }
909

    
910
        @Override
911
        public String[] getRequiredFieldNames() {
912
            return this.fieldNames;
913
        }
914

    
915
    }
916

    
917
    private void loadFeatures() throws IOException, DataException,
918
            CoercionException, CloneNotSupportedException {
919

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

    
943
    }
944
    
945
    private void loadFeatures(SimpleSequentialReader reader, ReaderData readerData) throws IOException, DataException,
946
            CoercionException, CloneNotSupportedException {
947

    
948
        TaskStatusManager manager = ToolsLocator.getTaskStatusManager();
949
        SimpleTaskStatus taskStatus = manager.createDefaultSimpleTaskStatus(reader.getName());
950
        taskStatus.setAutoremove(true);
951
        taskStatus.setIndeterminate();
952
        taskStatus.add();
953
        try {
954
            List<String> headers;
955

    
956
            taskStatus.message("_preparing");
957
            readerData.setName(reader.getName());
958
            
959
            boolean ignore_errors = getParameters().getIgnoreErrors();
960

    
961
            headers = getParameters().getFieldNames();
962
            if ( headers == null ) {
963
                headers = reader.getFieldNames();
964
            }
965

    
966
            // Initialize the feature types
967
            EditableFeatureType edftype = this.getFeatureType(headers, automaticDetectionOfTypes(reader));
968

    
969
            edftype.setLabel(reader.getLabel());
970
            edftype.setDescription(reader.getDescription());
971
            Map<String, String> tagsReader = reader.getTags();
972
            if( tagsReader!=null ) {
973
                Tags tagsType = edftype.getTags();
974
                for (Map.Entry<String, String> tag : tagsReader.entrySet()) {
975
                    tagsType.set(tag.getKey(), tag.getValue());
976
                }
977
            }
978
            
979
            FeatureType ftype = edftype.getNotEditableCopy();
980
            List<FeatureType> ftypes = new ArrayList<>();
981
            ftypes.add(ftype);
982
            readerData.setFeatureTypes(ftypes, ftype);
983

    
984
            Coercion coercion[] = new Coercion[ftype.size()];
985
            int sizes[] = new int[ftype.size()];
986
            for ( int i = 0; i < ftype.size(); i++ ) {
987
                sizes[i] = -1;
988
                FeatureAttributeDescriptor ad = ftype.getAttributeDescriptor(i);
989
                coercion[i] = ad.getDataType().getCoercion();
990
                if ( ad.getDataType().getType() == DataTypes.STRING ) {
991
                    if ( ad.getSize() == 0 ) {
992
                        // Es un string y no tiene un size asignado.
993
                        // Lo ponemos a cero para calcularlo.
994
                        sizes[i] = 0;
995
                    }
996
                }
997
            }
998
           
999
            if ( ftype.getDefaultGeometryAttributeName() != null ) {
1000
                readerData.setNeedCalculateEnvelope(true);
1001
            }
1002

    
1003
            Locale locale = getParameters().getLocale();
1004
            taskStatus.message("_loading");
1005
            long rowCount = reader.getRowCount();
1006
            if( rowCount >0 ) {
1007
                taskStatus.setRangeOfValues(0, rowCount);
1008
            }
1009

    
1010
            int count = 0;
1011

    
1012
            int count_errors = 0;
1013
            
1014
            reader.rewind();
1015
            List<Object> row = reader.read();
1016

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

    
1073
            taskStatus.terminate();
1074
        } catch (Exception ex) {
1075
            taskStatus.abort();
1076
            LOGGER.warn("Can't load features from '"+getProviderName()+"' file '" + getFullFileName() + "'.", ex);
1077
        }
1078
    }
1079
    
1080
    private int[] automaticDetectionOfTypes(SimpleSequentialReader reader) throws IOException {
1081
        boolean automatic_types_detection = getParameters().getAutomaticTypesDetection();
1082
        if ( !automatic_types_detection ) {
1083
            return null;
1084
        }
1085
        int[] types = null;
1086
        try {
1087
            reader.rewind();
1088
            List<String> fieldNames = reader.getFieldNames();
1089
            if ( fieldNames == null ) {
1090
                fieldNames = getParameters().getFieldNames();
1091
            }
1092

    
1093
            AutomaticDetectionOfTypes x = new AutomaticDetectionOfTypes(
1094
                    this.getFullFileName()
1095
            );
1096
            types = x.detect(
1097
                    fieldNames.size(), 
1098
                    reader, 
1099
                    false, 
1100
                    getParameters().getLocale()
1101
            );
1102
        } catch (Exception ex) {
1103
            throw new RuntimeException("Problems reading '"+getProviderName()+"' file '" + getFullFileName() + "'.", ex);
1104
        }
1105
        return types;
1106
    }
1107

    
1108
    @Override
1109
    public boolean hasDynValue(String name) {
1110
        if ( DataStore.METADATA_ENVELOPE.equalsIgnoreCase(name) ) {
1111
            return true;
1112
        } else if ( DataStore.METADATA_CRS.equalsIgnoreCase(name) ) {
1113
            return true;
1114
        }
1115
        return super.hasDynValue(name);
1116
    }
1117

    
1118
    @Override
1119
    public UnmodifiableBasicMap<String, DataStore> getChildren() {
1120
        return new Children();
1121
    }
1122

    
1123
}