Statistics
| Revision:

gvsig-gdal / trunk / org.gvsig.gdal / org.gvsig.gdal.gpx / src / main / java / org / gvsig / fmap / dal / store / gpx / OGRStoreProvider.java @ 99

History | View | Annotate | Download (19.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.store.gpx;
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.List;
31

    
32
import org.apache.commons.io.FilenameUtils;
33
import org.apache.commons.lang3.StringUtils;
34
import org.gdal.gdal.gdal;
35
import org.gdal.ogr.DataSource;
36
import org.gdal.ogr.Driver;
37
import org.gdal.ogr.FeatureDefn;
38
import org.gdal.ogr.Layer;
39
import org.gdal.ogr.ogr;
40
import org.gvsig.fmap.dal.DALLocator;
41
import org.gvsig.fmap.dal.DataManager;
42
import org.gvsig.fmap.dal.DataServerExplorer;
43
import org.gvsig.fmap.dal.DataStoreNotification;
44
import org.gvsig.fmap.dal.DataTypes;
45
import org.gvsig.fmap.dal.FileHelper;
46
import org.gvsig.fmap.dal.exception.DataException;
47
import org.gvsig.fmap.dal.exception.InitializeException;
48
import org.gvsig.fmap.dal.exception.OpenException;
49
import org.gvsig.fmap.dal.exception.ReadException;
50
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
51
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
52
import org.gvsig.fmap.dal.feature.EditableFeatureType;
53
import org.gvsig.fmap.dal.feature.Feature;
54
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
55
import org.gvsig.fmap.dal.feature.FeatureStore;
56
import org.gvsig.fmap.dal.feature.FeatureType;
57
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
58
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProviderServices;
59
import org.gvsig.fmap.dal.feature.spi.memory.AbstractMemoryStoreProvider;
60
import org.gvsig.fmap.dal.resource.file.FileResource;
61
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
62
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
63
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorer;
64
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorerParameters;
65
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
66
import org.gvsig.fmap.geom.Geometry;
67
import org.gvsig.fmap.geom.GeometryException;
68
import org.gvsig.fmap.geom.GeometryLocator;
69
import org.gvsig.fmap.geom.GeometryManager;
70
import org.gvsig.fmap.geom.exception.CreateGeometryException;
71
import org.gvsig.fmap.geom.primitive.Envelope;
72
import org.gvsig.fmap.geom.type.GeometryType;
73
import org.gvsig.tools.ToolsLocator;
74
import org.gvsig.tools.dataTypes.CoercionException;
75
import org.gvsig.tools.dataTypes.DataTypesManager;
76
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
77
import org.gvsig.tools.exception.BaseException;
78
import org.gvsig.tools.exception.NotYetImplemented;
79
import org.gvsig.tools.locator.LocatorException;
80
import org.gvsig.tools.persistence.PersistentState;
81
import org.gvsig.tools.persistence.exception.PersistenceException;
82
import org.gvsig.tools.task.SimpleTaskStatus;
83
import org.gvsig.tools.task.TaskStatusManager;
84
import org.gvsig.tools.visitor.VisitCanceledException;
85
import org.gvsig.tools.visitor.Visitor;
86
import org.slf4j.Logger;
87
import org.slf4j.LoggerFactory;
88

    
89

    
90
public class OGRStoreProvider extends AbstractMemoryStoreProvider implements
91
ResourceConsumer {
92
    private static final Logger logger = LoggerFactory.getLogger(OGRStoreProvider.class);
93

    
94
    public static final String NAME = "OGR_DRIVER";
95
    public static final String DESCRIPTION = "GPX file";
96

    
97
    public static final String METADATA_DEFINITION_NAME = NAME;
98

    
99
    private ResourceProvider resource;
100

    
101
    private long counterNewsOIDs = 0;
102
    private Envelope envelope;
103
    private boolean need_calculate_envelope = false;
104
    private SimpleTaskStatus taskStatus;
105

    
106

    
107
    public OGRStoreProvider(OGRStoreParameters parameters,
108
        DataStoreProviderServices storeServices) throws InitializeException {
109
        super(
110
            parameters, 
111
            storeServices,
112
            FileHelper.newMetadataContainer(METADATA_DEFINITION_NAME)
113
        );
114
        
115
        gdal.AllRegister();
116
                ogr.RegisterAll();
117

    
118
        TaskStatusManager manager = ToolsLocator.getTaskStatusManager();
119
        this.taskStatus = manager.createDefaultSimpleTaskStatus("Driver");
120

    
121
        counterNewsOIDs = 0;
122

    
123
        File file = getDriverParameters().getFile();
124
        resource = this.createResource(
125
            FileResource.NAME,
126
            new Object[] { file.getAbsolutePath() }
127
        );
128

    
129
        resource.addConsumer(this);
130
        initializeFeatureTypes();
131
    }
132

    
133
    private OGRStoreParameters getDriverParameters() {
134
        return (OGRStoreParameters) this.getParameters();
135
    }
136

    
137
    public String getProviderName() {
138
        return NAME;
139
    }
140

    
141
    public boolean allowWrite() {
142
        return false;
143
    }
144

    
145
    private String getFullFileName() {
146
            // Usar solo para mostrar mensajes en el logger.
147
                String s = "(unknow)";
148
                try { 
149
                        s = getDriverParameters().getFile().getAbsolutePath();
150
                } catch(Exception e2) {
151
                        s = "(unknow)";
152
                }
153
                return s;
154
    }
155
    
156
    public void open() throws OpenException {
157
        if (this.data != null) {
158
            return;
159
        }
160
        this.data = new ArrayList<FeatureProvider>();
161
        resource.setData(new HashMap());
162
        counterNewsOIDs = 0;
163
                try {
164
                        loadFeatures();
165
                } catch (RuntimeException e) {
166
                        logger.warn("Can't load features from Driver '"+getFullFileName()+"'.", e);
167
                        throw e;
168
                } catch (Exception e) {
169
                        logger.warn("Can't load features from Driver '"+getFullFileName()+"'.", e);
170
                        throw new RuntimeException(e);
171
                }
172
    }
173

    
174
    public DataServerExplorer getExplorer() throws ReadException {
175
        DataManager manager = DALLocator.getDataManager();
176
        FilesystemServerExplorerParameters params;
177
        try {
178
            params = (FilesystemServerExplorerParameters) manager
179
            .createServerExplorerParameters(FilesystemServerExplorer.NAME);
180
            params.setRoot(this.getDriverParameters().getFile().getParent());
181
            return manager.openServerExplorer(FilesystemServerExplorer.NAME,params);
182
        } catch (DataException e) {
183
            throw new ReadException(this.getProviderName(), e);
184
        } catch (ValidateDataParametersException e) {
185
            throw new ReadException(this.getProviderName(), e);
186
        }
187

    
188
    }
189

    
190
    public boolean closeResourceRequested(ResourceProvider resource) {
191
        return true;
192
    }
193

    
194
    public int getOIDType() {
195
        return DataTypes.LONG;
196
    }
197

    
198
    public boolean supportsAppendMode() {
199
        return false;
200
    }
201

    
202
    public void append(FeatureProvider featureProvider) {
203
            throw new UnsupportedOperationException();
204
    }
205

    
206
    public void beginAppend() {
207
            throw new UnsupportedOperationException();
208
    }
209

    
210
    public void endAppend() {
211
            throw new UnsupportedOperationException();
212
    }
213

    
214
    public void saveToState(PersistentState state) throws PersistenceException {
215
        throw new NotYetImplemented();
216
    }
217

    
218
    public void loadFromState(PersistentState state) throws PersistenceException {
219
        throw new NotYetImplemented();
220
    }
221

    
222
    public Object createNewOID() {
223
        return new Long(counterNewsOIDs++);
224
    }
225

    
226
    protected void initializeFeatureTypes() throws InitializeException {
227
        try {
228
            this.open();
229
        } catch (OpenException e) {
230
            throw new InitializeException(this.getProviderName(), e);
231
        }
232
    }
233

    
234
    public Envelope getEnvelope() throws DataException {
235
        this.open();
236
        if( this.envelope!= null )  {
237
                return this.envelope;
238
        }
239
        if( !this.need_calculate_envelope ) {
240
                return null;
241
        }
242
        FeatureStore fs = this.getFeatureStore();
243
        FeatureType ft = fs.getDefaultFeatureType();
244
        FeatureAttributeDescriptor fad = ft.getAttributeDescriptor(ft.getDefaultGeometryAttributeIndex());
245

    
246
        try {
247
            this.envelope = GeometryLocator.getGeometryManager().createEnvelope(fad.getGeomType().getSubType());
248
                        fs.accept(new Visitor() {
249
                                public void visit(Object obj) throws VisitCanceledException, BaseException {
250
                                        Feature f = (Feature) obj;
251
                                        Geometry geom = f.getDefaultGeometry();
252
                                        envelope.add(geom.getEnvelope());
253
                                }
254
                        });
255
                } catch (BaseException e) {
256
                        logger.warn("Can't calculate the envelope of GPX file '"+this.getFullName()+"'.",e);
257
                        this.envelope = null;
258
                }
259
        
260
        this.need_calculate_envelope = false;
261
        return this.envelope;
262
    }
263

    
264
    public Object getDynValue(String name) throws DynFieldNotFoundException {
265
//        if( DataStore.METADATA_ENVELOPE.equalsIgnoreCase(name) ) {
266
//            try {
267
//                return this.getEnvelope();
268
//            } catch (DataException e) {
269
//                return null;
270
//            }
271
//        } else {
272
//            if( DataStore.METADATA_CRS.equalsIgnoreCase(name) ) {
273
//                IProjection pro = DriverStoreParameters.getCRS(this.getDriverParameters());
274
//                if (pro != null){
275
//                    return pro;
276
//                }
277
//            }
278
//        }
279
        return super.getDynValue(name);
280
    }
281

    
282

    
283
    public void resourceChanged(ResourceProvider resource) {
284
        this.getStoreServices().notifyChange(
285
            DataStoreNotification.RESOURCE_CHANGED,
286
            resource);
287
    }
288

    
289

    
290
    public Object getSourceId() {
291
        return this.getDriverParameters().getFile();
292
    }
293

    
294
    public String getName() {
295
        String name = this.getDriverParameters().getFile().getName();
296
        return FilenameUtils.getBaseName(name);
297
    }
298

    
299
    public String getFullName() {
300
        return this.getDriverParameters().getFile().getAbsolutePath();
301
    }
302

    
303
    public ResourceProvider getResource() {
304
        return resource;
305
    }
306

    
307
    
308
        private void loadFeatures() throws IOException, DataException,
309
                        CoercionException, CloneNotSupportedException {
310
                
311
                boolean bReadOnly = false;
312
                boolean bVerbose = false;
313
                File file = this.getDriverParameters().getFile();
314
                String pszDataSource = file.getAbsolutePath();
315
                
316
                DataSource poDS = ogr.Open(pszDataSource, !bReadOnly);
317
            if (poDS == null && !bReadOnly){
318
                poDS = ogr.Open(pszDataSource, false);
319
                if (poDS == null && bVerbose){
320
                        logger.warn( "Had to open data source read-only.");
321
                }
322
            }
323
        
324
           if(poDS == null){        
325
                   logger.warn(file +" -> Unable to open datasource " + 
326
                         "with the available drivers.");
327
             
328
             if(ogr.GetDriverCount() == 0){
329
                     logger.warn("ERROR: no drivers availables");
330
             }
331
                     
332
           }
333
            
334
            if(poDS != null){ 
335
                    Driver poDriver = poDS.GetDriver();
336
                    logger.warn(file + " -> Opened using driver '" + poDriver.GetName() + "' successfully.");
337
                    
338
                    // Initialize the feature types
339
                    FeatureStoreProviderServices store = this.getStoreServices();
340
                    
341
                    for(int ij=0; ij<poDS.GetLayerCount(); ij++){
342
                            Layer layer = poDS.GetLayer(ij);
343
                            FeatureDefn layerDef = layer.GetLayerDefn();
344
                            
345
                            String[] headers = new String[layerDef.GetFieldCount()];
346
                            int[] types = new int[layerDef.GetFieldCount()];
347
                            for(int ji=0; ji<layerDef.GetFieldCount(); ji++){
348
                                    headers[ji] = layerDef.GetFieldDefn(ji).GetName(); 
349
                                    types[ji]  = layerDef.GetFieldDefn(ji).GetFieldType();
350
                            }
351
                            
352
                            EditableFeatureType edftype = this.getFeatureType(headers, types);
353
                            String geomColumn = layer.GetGeometryColumn();
354
                            if(!StringUtils.isBlank(geomColumn)){
355
                                    edftype.setDefaultGeometryAttributeName(layer.GetGeometryColumn());
356
                            }else{
357
                                    edftype.setDefaultGeometryAttributeName("GEOM");
358
                            }
359
                            
360
                    FeatureType ftype = edftype.getNotEditableCopy();
361
                    List<FeatureType> ftypes = new ArrayList<FeatureType>();
362
                    ftypes.add(ftype);
363
                    store.setFeatureTypes(ftypes, ftype);
364
        
365
                    if ( ftype.getDefaultGeometryAttributeName() != null ) {
366
                        this.need_calculate_envelope = true;
367
                    }
368
                    
369
                    taskStatus.message("_loading");
370
                    int count = 0;
371
                    int count_errors = 0;
372
                    boolean ignore_errors = false;
373
                    
374
                    if(layer.GetFeatureCount()>0){
375
                            org.gdal.ogr.Feature row = layer.GetNextFeature();
376
                            while ( row != null ) {
377
                                taskStatus.setCurValue(++count);
378
                                FeatureProvider feature = this.createFeatureProvider(ftype);
379
                                for ( int i = 0; i < row.GetFieldCount(); i++ ) {
380
                                    try {
381
                                        feature.set(i, this.getFieldValue(row, i));
382
                                    } catch (RuntimeException ex) {
383
                                        if ( !ignore_errors ) {
384
                                            throw ex;
385
                                        }
386
                                        if ( count_errors++ < 10 ) {
387
                                            logger.warn("Can't load value of attribute " + i + " in row " + count + ".", ex);
388
                                        }
389
                                        if ( count_errors == 10 ) {
390
                                            logger.info("Too many errors, suppress messages.");
391
                                        }
392
                                    }
393
                                }
394
                                org.gdal.ogr.Geometry geom = row.GetGeometryRef();
395
                            if(geom != null){
396
                                    Geometry geometry;
397
                                                        try {
398
                                                                geometry = GeometryLocator.getGeometryManager().createFrom(geom.ExportToWkt());
399
                                                                feature.setDefaultGeometry(geometry);
400
                                                        } catch (CreateGeometryException e) {
401
                                                                // TODO Auto-generated catch block
402
                                                                e.printStackTrace();
403
                                                        } catch (LocatorException e) {
404
                                                                // TODO Auto-generated catch block
405
                                                                e.printStackTrace();
406
                                                        } catch (GeometryException e) {
407
                                                                // TODO Auto-generated catch block
408
                                                                e.printStackTrace();
409
                                                        }
410
                                    
411
                            }
412
                                this.addFeatureProvider(feature);
413
                                row = layer.GetNextFeature();
414
                            }
415
                    }
416

    
417
                    taskStatus.terminate();
418
                    }
419
            }
420
        }
421
        
422
        
423
    private Object getFieldValue(org.gdal.ogr.Feature row, int i) {
424
                int gdalType = row.GetDefnRef().GetFieldDefn(i).GetFieldType();
425
                switch(this.getFieldType(gdalType)){
426
                        case DataTypes.STRING:
427
                                return row.GetFieldAsString(i);
428
                        case DataTypes.INT:
429
                                return row.GetFieldAsInteger(i);
430
                        default:
431
                                return row.GetFieldAsString(i);
432
                }
433
        }
434

    
435
        private EditableFeatureType getFeatureType(String headers[], int automaticTypes[]) {
436
        EditableFeatureType fType = getStoreServices().createFeatureType(this.getName());
437
        fType.setHasOID(true);
438
        DataTypesManager dataTypesManager = ToolsLocator.getDataTypesManager();
439

    
440
        FieldTypeParser[] fieldTypes = new FieldTypeParser[headers.length];
441
        //
442
        // Calculamos cuales pueden ser los tipos de datos
443
        //
444
        for ( int i = 0; i < fieldTypes.length; i++ ) {
445
            fieldTypes[i] = new FieldTypeParser(headers[i], this.getFieldType(automaticTypes[i]));
446
        }
447

    
448
        //
449
        // Una vez ya sabemos los tipos de datos rellenamos el feature-type
450
        //
451
        for ( int i = 0; i < fieldTypes.length; i++ ) {
452
            EditableFeatureAttributeDescriptor fad = fType.add(
453
                    fieldTypes[i].name,
454
                    fieldTypes[i].type
455
            );
456
            fad.setSize(fieldTypes[i].size);
457
            fad.setAllowNull(fieldTypes[i].allowNulls);
458
            if ( fieldTypes[i].type == DataTypes.GEOMETRY
459
                    && fType.getDefaultGeometryAttributeName() == null ) {
460
                fType.setDefaultGeometryAttributeName(fieldTypes[i].name);
461
            }
462
        }
463
        EditableFeatureAttributeDescriptor attr = fType.add("GEOM", DataTypes.GEOMETRY);
464
        GeometryManager geommgr = GeometryLocator.getGeometryManager();
465
        GeometryType gt;
466
        try {
467
                gt = geommgr.getGeometryType(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D);
468

    
469
                attr.setGeometryType(gt);
470
        } catch (Exception e) {
471
                logger.warn("Can't set geometry type for the calculated field in GPX file '" + getFullFileName() + "'.", e);
472
        }
473
        return fType;
474
    }
475

    
476
        
477
        private int getFieldType(int gdalType) {
478
                switch(gdalType){
479
                        case 2:
480
                                return DataTypes.FLOAT;
481
                        case 11:
482
                                return DataTypes.DATE;
483
                        case 4: 
484
                                return DataTypes.STRING;
485
                        default: 
486
                                return DataTypes.STRING; 
487
                }
488
        }
489

    
490
        public String getDriver(int index){
491
                return ogr.GetDriver(index).getName();
492
        }
493
        
494
        public int getDriverCount(){
495
                return ogr.GetDriverCount();
496
        }
497
        
498
         public List<String> getAvailableDrivers(){
499
                 List<String> aux = new ArrayList<String>();
500
             for(int iDriver = 0; iDriver < ogr.GetDriverCount(); iDriver++ ){
501
                 aux.add( ogr.GetDriver(iDriver).GetName() );
502
             }
503
             return aux;
504
         }
505

    
506
         public String getOGRVersion(){
507
                 return gdal.VersionInfo();
508
         }
509
         
510
         
511
         
512
         private class FieldTypeParser {
513

    
514
                public String name = null;
515
                public int type = DataTypes.STRING;
516
                public int size = 0;
517
                public boolean allowNulls = true;
518

    
519
                private String typename = "string";
520

    
521
                FieldTypeParser(String name, int type) {
522
                        this.name = name;
523
                        this.type = type;
524
                }
525

    
526
                private int getType(String value) {
527
                    DataTypesManager dataTypesManager = ToolsLocator.getDataTypesManager();
528
                    return dataTypesManager.getType(typename);
529
                }
530

    
531
                // El formato seria:
532
                //   name[:typename[:size[:notnull|null]]]
533
                //   name[__typename[__size[__notnull|null]]]
534
                //
535
                public boolean parse(String value) {
536
                    String typename = null;
537
                    String[] ss = null;
538
                    if ( value.contains(":") ) {
539
                        ss = value.split(":");
540
                    } else if ( value.contains("__") ) {
541
                        ss = value.split("__");
542
                    }
543
                    if ( ss == null ) {
544
                        this.name = value;
545
                        return true;
546
                    }
547
                    switch (ss.length) {
548
                    case 4:
549
                        if ( ss[3].length() > 0 ) {
550
                            if ( "notnull".equalsIgnoreCase(ss[3]) ) {
551
                                this.allowNulls = false;
552
                            } else {
553
                                this.allowNulls = true;
554
                            }
555
                        }
556
                    case 3:
557
                        if ( ss[2].length() > 0 ) {
558
                            try {
559
                                this.size = Integer.parseInt(ss[2]);
560
                            } catch (Exception ex) {
561
                                logger.warn("Ignore incorrect field size for field " + value + " in JExcel header of '" + getFullFileName() + "'.", ex);
562
                            }
563
                        }
564
                    case 2:
565
                        if ( ss[1].length() > 0 ) {
566
                            this.typename = ss[1];
567
                            this.type = this.getType(this.typename);
568
                            if ( this.type == DataTypes.INVALID ) {
569
                                this.type = DataTypes.STRING;
570
                                logger.info("Type '" + typename + "' not valid for attribute '" + value + "' in JExcel file '" + getFullFileName() + "'.");
571
                            }
572
                        }
573
                    case 1:
574
                        this.name = ss[0];
575
                        break;
576
                    }
577

    
578
                    if ( this.type != DataTypes.STRING ) {
579
                        this.size = 0;
580
                    }
581
                    return true;
582
                }
583

    
584
            }
585
         
586
}