Statistics
| Revision:

gvsig-gdal / trunk / org.gvsig.gdal / org.gvsig.gdal.prov / org.gvsig.gdal.prov.ogr / src / main / java / org / gvsig / gdal / prov / ogr / OGRDataStoreProvider.java @ 297

History | View | Annotate | Download (23.3 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright ? 2007-2016 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 2
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.gdal.prov.ogr;
25

    
26
import java.util.ArrayList;
27
import java.util.Iterator;
28
import java.util.List;
29

    
30
import org.apache.commons.lang3.StringUtils;
31
import org.gdal.ogr.DataSource;
32
import org.gdal.ogr.Feature;
33
import org.gdal.ogr.FeatureDefn;
34
import org.gdal.ogr.FieldDefn;
35
import org.gdal.ogr.GeomFieldDefn;
36
import org.gdal.ogr.Geometry;
37
import org.gdal.ogr.Layer;
38
import org.gdal.ogr.ogr;
39
import org.gdal.ogr.ogrConstants;
40

    
41
import org.gvsig.fmap.dal.DataStore;
42
import org.gvsig.fmap.dal.DataStoreParameters;
43
import org.gvsig.fmap.dal.DataTypes;
44
import org.gvsig.fmap.dal.FileHelper;
45
import org.gvsig.fmap.dal.exception.DataException;
46
import org.gvsig.fmap.dal.exception.InitializeException;
47
import org.gvsig.fmap.dal.exception.OpenException;
48
import org.gvsig.fmap.dal.exception.ReadRuntimeException;
49
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
50
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
51
import org.gvsig.fmap.dal.feature.FeatureQuery;
52
import org.gvsig.fmap.dal.feature.FeatureQueryOrder;
53
import org.gvsig.fmap.dal.feature.FeatureQueryOrder.FeatureQueryOrderMember;
54
import org.gvsig.fmap.dal.feature.FeatureType;
55
import org.gvsig.fmap.dal.feature.spi.AbstractFeatureStoreProvider;
56
import org.gvsig.fmap.dal.feature.spi.DefaultFeatureProvider;
57
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
58
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
59
import org.gvsig.fmap.dal.feature.spi.FeatureSetProvider;
60
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProvider;
61
import org.gvsig.fmap.dal.resource.ResourceAction;
62
import org.gvsig.fmap.dal.resource.file.FileResource;
63
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
64
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
65
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
66
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
67
import org.gvsig.fmap.geom.GeometryLocator;
68
import org.gvsig.fmap.geom.primitive.Envelope;
69
import org.gvsig.fmap.geom.type.GeometryTypeNotSupportedException;
70
import org.gvsig.fmap.geom.type.GeometryTypeNotValidException;
71
import org.gvsig.tools.dynobject.DynObject;
72
import org.gvsig.tools.evaluator.Evaluator;
73
import org.gvsig.tools.exception.BaseException;
74

    
75
import org.slf4j.Logger;
76
import org.slf4j.LoggerFactory;
77

    
78
/**
79
 *
80
 * @author <a href="mailto:lmarques@disid.com">Lluis Marques</a>
81
 *
82
 */
83
public class OGRDataStoreProvider extends AbstractFeatureStoreProvider implements
84
    FeatureStoreProvider, ResourceConsumer {
85

    
86
    private static final Logger LOG = LoggerFactory.getLogger(OGRDataStoreProvider.class);
87

    
88
    /**
89
     *
90
     */
91
    public static final String METADATA_DEFINITION_NAME = "OGRDataStoreProvider";
92

    
93
    /**
94
     *
95
     */
96
    public static final String NAME = "OGRDataStoreProvider";
97

    
98
    /**
99
     *
100
     */
101
    public static final String DESCRIPTION = "OGR provider to open vectorial resources";
102

    
103
    protected DataSource dataSource;
104

    
105
    private Envelope envelope;
106

    
107
    private Layer newLayer;
108

    
109
    protected ResourceProvider resourceProvider;
110

    
111
    private Boolean updateSupport;
112

    
113
    private boolean opened = false;
114

    
115
    protected OGRDataStoreProvider(DataStoreParameters dataParameters,
116
        DataStoreProviderServices storeServices, DynObject metadata) throws InitializeException {
117
        super(dataParameters, storeServices, metadata);
118

    
119
        // Set CRS parameter to metadata
120
        this.setDynValue(DataStore.METADATA_CRS, dataParameters.getDynValue(DataStore.METADATA_CRS));
121

    
122
        getResource().addConsumer(this);
123

    
124
        try {
125
            this.open();
126
        } catch (OpenException e) {
127
            throw new InitializeException(NAME, e);
128
        }
129
    }
130

    
131
    protected OGRDataStoreProvider(DataStoreParameters dataParameters,
132
        DataStoreProviderServices storeServices) throws InitializeException {
133
        this(dataParameters, storeServices, FileHelper
134
            .newMetadataContainer(METADATA_DEFINITION_NAME));
135
    }
136

    
137
    /*
138
     * Lazy initialization of data source
139
     */
140
    protected synchronized DataSource getDataSource() throws OGRUnsupportedFormatException {
141
        if (this.dataSource == null) {
142

    
143
            // Prioritize connection string over file
144
            if (StringUtils.isNotBlank(getOGRParameters().getConnectionString())) {
145

    
146
                // Trying to open in update mode
147
                this.dataSource = ogr.Open(getOGRParameters().getConnectionString(), 1);
148

    
149
                if (this.dataSource == null) {
150
                    this.dataSource = ogr.Open(getOGRParameters().getConnectionString());
151
                    updateSupport = false;
152
                } else {
153
                    updateSupport = true;
154
                }
155

    
156
            } else if (getOGRParameters().getFile() != null
157
                && getOGRParameters().getFile().exists()) {
158

    
159
                // Trying to open in update mode
160
                this.dataSource = ogr.Open(getOGRParameters().getFile().getAbsolutePath(), 1);
161

    
162
                if (this.dataSource == null) {
163
                    this.dataSource = ogr.Open(getOGRParameters().getFile().getAbsolutePath());
164
                    updateSupport = false;
165
                } else {
166
                    updateSupport = true;
167
                }
168

    
169
            } else {
170
                throw new IllegalStateException(
171
                    "Invalid parameters. Connection string must not be blank or file must exists");
172
            }
173
        }
174

    
175
        if (this.dataSource == null) {
176

    
177
            if (StringUtils.isNotBlank(getOGRParameters().getConnectionString())) {
178
                throw new OGRUnsupportedFormatException(getOGRParameters().getConnectionString());
179
            }
180
        }
181

    
182
        return this.dataSource;
183
    }
184

    
185
    /*
186
     * Lazy initialization of update support flag
187
     */
188
    private Boolean hasUpdateSupport() throws OGRUnsupportedFormatException {
189
        if (this.updateSupport == null) {
190
            getDataSource();
191
        }
192
        return this.updateSupport;
193
    }
194

    
195
    /*
196
     * Lazy initialization of layer
197
     */
198
    protected Layer getLayer() throws OGRUnsupportedFormatException {
199
        if (this.newLayer == null) {
200
            this.newLayer = getDataSource().GetLayer(getOGRParameters().getLayerName());
201
            // this.layer = getDataSource().GetLayer(0);
202
            if (this.newLayer == null) {
203
                LOG.warn("Can not get layer with {} name. Get first layer of data source",
204
                    getOGRParameters().getLayerName());
205
                this.newLayer = getDataSource().GetLayer(0);
206
                getOGRParameters().setLayerName(this.newLayer.GetName());
207
            }
208
        }
209
        return this.newLayer;
210
    }
211

    
212
    /*
213
     * Lazy envelope initialization
214
     */
215
    @Override
216
    public Envelope getEnvelope() throws DataException {
217
        open();
218
        if (this.envelope == null) {
219
            this.envelope = (Envelope) getResource().execute(new ResourceAction() {
220

    
221
                @Override
222
                public Object run() throws Exception {
223
                    Layer layer = getLayer();
224
                    double[] extent = layer.GetExtent(true);
225
                    if (extent != null) {
226
                        return GeometryLocator.getGeometryManager().createEnvelope(extent[0],
227
                            extent[2], extent[1], extent[3], SUBTYPES.GEOM2D);
228
                    } else {
229
                        Envelope tmpEnvelope =
230
                            GeometryLocator.getGeometryManager().createEnvelope(SUBTYPES.GEOM2D);
231
                        FeatureType featureType = getStoreServices().getDefaultFeatureType();
232
                        layer.ResetReading();
233
                        Feature feature = layer.GetNextFeature();
234
                        while (feature!=null) {
235
                            double[] envelope = new double[4];
236
                            int geomFieldIndex =
237
                                layer.GetLayerDefn().GetGeomFieldIndex(
238
                                    featureType.getDefaultGeometryAttributeName());
239
                            Geometry ogrGeometry = feature.GetGeomFieldRef(geomFieldIndex);
240
                            ogrGeometry.GetEnvelope(envelope);
241
                            tmpEnvelope.add(GeometryLocator.getGeometryManager()
242
                                .createEnvelope(envelope[0], envelope[2], envelope[1], envelope[3],
243
                                    SUBTYPES.GEOM2D));
244
                            feature = layer.GetNextFeature();
245
                        }
246

    
247
                        return tmpEnvelope;
248
                    }
249
                }
250
            });
251
        }
252
        return this.envelope;
253
    }
254

    
255
    @Override
256
    public String getFullName() {
257

    
258
        StringBuilder stb = new StringBuilder();
259
        stb.append(NAME);
260
        stb.append(":");
261
        if (StringUtils.isBlank(getOGRParameters().getConnectionString())) {
262
            stb.append(getOGRParameters().getFile().getAbsolutePath());
263
            stb.append(":");
264
            stb.append(getOGRParameters().getLayerName());
265
        } else {
266
            stb.append(getOGRParameters().getConnectionString());
267
        }
268
        return stb.toString();
269
    }
270

    
271
    @Override
272
    public String getName() {
273
        return getOGRParameters().getLayerName();
274
    }
275

    
276
    @Override
277
    public String getProviderName() {
278
        return NAME;
279
    }
280

    
281
    @Override
282
    public boolean allowWrite() {
283
        try {
284
            return getLayer().TestCapability(ogrConstants.OLCAlterFieldDefn)
285
                && getLayer().TestCapability(ogrConstants.OLCCreateField)
286
                && getLayer().TestCapability(ogrConstants.OLCDeleteField)
287
                && getLayer().TestCapability(ogrConstants.OLCDeleteFeature) && hasUpdateSupport();
288
        } catch (OGRUnsupportedFormatException e) {
289
            LOG.error("Can not determinate if data source allows write", e);
290
            return false;
291
        }
292
    }
293

    
294
    @Override
295
    public ResourceProvider getResource() {
296

    
297
        if (this.resourceProvider == null) {
298
            if (StringUtils.isBlank(getOGRParameters().getConnectionString())) {
299
                try {
300
                    this.resourceProvider =
301
                        this.createResource(FileResource.NAME, new Object[] { getOGRParameters()
302
                            .getFile().getAbsolutePath() });
303
                } catch (InitializeException e) {
304
                    throw new ReadRuntimeException(String.format(
305
                        "Can not create file resource with %1s path", getOGRParameters().getFile()
306
                            .getAbsolutePath()), e);
307
                }
308
            } else {
309
                try {
310
                    this.resourceProvider =
311
                        this.createResource(OGRResource.NAME, new Object[] { getOGRParameters()
312
                            .getConnectionString() });
313
                } catch (InitializeException e) {
314
                    throw new ReadRuntimeException(String.format(
315
                        "Can not create OGR resource with %1s", getOGRParameters()
316
                            .getConnectionString()), e);
317
                }
318
            }
319
        }
320

    
321
        return resourceProvider;
322
    }
323

    
324
    @Override
325
    public Object getSourceId() {
326
        return this.getOGRParameters().getFile();
327
    }
328

    
329
    @Override
330
    public void open() throws OpenException {
331

    
332
        if (opened == false) {
333
            try {
334
                this.opened = loadFeatureType();
335
            } catch (BaseException e) {
336
                LOG.error("Can not load feature type", e);
337
                throw new OpenException(getFullName(), e);
338
            }
339
        }
340
    }
341

    
342
    protected boolean loadFeatureType() throws OGRUnsupportedFormatException,
343
        GeometryTypeNotSupportedException, GeometryTypeNotValidException {
344

    
345
        return (boolean) getResource().execute(new ResourceAction() {
346

    
347
            @Override
348
            public Object run() throws Exception {
349
                FeatureDefn featureDefn = getLayer().GetLayerDefn();
350
                OGRConverter converter = new OGRConverter();
351
                String defaultGeometryField = getOGRParameters().getDefaultGeometryField();
352
                FeatureType featureType = converter.convert(featureDefn, defaultGeometryField);
353

    
354
                if (featureType.getDefaultSRS() != null) {
355
                    setDynValue(DataStore.METADATA_CRS, featureType.getDefaultSRS());
356
                }
357

    
358
                List<FeatureType> featureTypes = new ArrayList<FeatureType>();
359
                featureTypes.add(featureType);
360

    
361
                getStoreServices().setFeatureTypes(featureTypes, featureType);
362
                return true;
363
            }
364
        });
365
    }
366

    
367
    @SuppressWarnings("rawtypes")
368
    @Override
369
    public void performChanges(final Iterator deleteds, final Iterator inserteds,
370
        final Iterator updateds, final Iterator featureTypesChanged) throws DataException {
371

    
372
        getResource().execute(new ResourceAction() {
373

    
374
            @Override
375
            public Object run() throws Exception {
376
                OGRConverter converter = new OGRConverter();
377

    
378
                if (getLayer().TestCapability(ogrConstants.OLCTransactions)) {
379
                    getLayer().StartTransaction();
380
                }
381

    
382
                while (featureTypesChanged.hasNext()) {
383
                    FeatureTypeChanged featureTypeChange =
384
                        (FeatureTypeChanged) featureTypesChanged.next();
385
                    FeatureType source = featureTypeChange.getSource();
386
                    FeatureType target = featureTypeChange.getTarget();
387

    
388
                    for (int i = 0; i < source.getAttributeDescriptors().length; i++) {
389
                        EditableFeatureAttributeDescriptor eAttDescriptor =
390
                            source.getEditable().getEditableAttributeDescriptor(i);
391

    
392
                        if (eAttDescriptor.getOriginalName() != null) {
393
                            int index =
394
                                getLayer().GetLayerDefn().GetFieldIndex(
395
                                    eAttDescriptor.getOriginalName());
396

    
397
                            FieldDefn field = converter.convertField(eAttDescriptor);
398
                            getLayer().AlterFieldDefn(index, field, ogrConstants.ALTER_ALL_FLAG);
399
                        } else if (target.getAttributeDescriptor(eAttDescriptor.getName()) == null) {
400
                            int index = getLayer().FindFieldIndex(eAttDescriptor.getName(), 1);
401
                            getLayer().DeleteField(index);
402
                        }
403
                    }
404

    
405
                    List<FieldDefn> fields = converter.convertFields(target);
406
                    for (FieldDefn fieldDefn : fields) {
407
                        int index = getLayer().GetLayerDefn().GetFieldIndex(fieldDefn.GetName());
408
                        if (index == -1) {
409
                            getLayer().CreateField(fieldDefn);
410
                        } else {
411
                            getLayer()
412
                                .AlterFieldDefn(index, fieldDefn, ogrConstants.ALTER_ALL_FLAG);
413
                        }
414
                    }
415

    
416
                    if (getLayer().TestCapability(ogrConstants.OLCCreateGeomField)) {
417
                        List<GeomFieldDefn> geometryFields =
418
                            converter.convertGeometryFields(target, true);
419
                        for (GeomFieldDefn geomFieldDefn : geometryFields) {
420
                            int index =
421
                                getLayer().GetLayerDefn()
422
                                    .GetGeomFieldIndex(geomFieldDefn.GetName());
423
                            if (index == -1) {
424
                                getLayer().CreateGeomField(geomFieldDefn);
425
                            }
426
                        }
427
                    } else {
428
                        StringBuilder stb = new StringBuilder();
429
                        stb.append("Driver '");
430
                        stb.append(getDataSource().GetDriver().GetName());
431
                        stb.append("' does not support create geometry fields");
432
                        LOG.warn(stb.toString());
433
                    }
434
                }
435

    
436
                while (deleteds.hasNext()) {
437
                    FeatureReferenceProviderServices reference =
438
                        (FeatureReferenceProviderServices) deleteds.next();
439
                    getLayer().DeleteFeature((int) reference.getOID());
440
                }
441

    
442
                while (inserteds.hasNext()) {
443
                    FeatureProvider featureProvider = (FeatureProvider) inserteds.next();
444
                    getLayer().CreateFeature(converter.convert(featureProvider));
445
                }
446

    
447
                while (updateds.hasNext()) {
448
                    FeatureProvider featureProvider = (FeatureProvider) updateds.next();
449
                    Feature ogrFeature = converter.convert(featureProvider);
450
                    getLayer().SetFeature(ogrFeature);
451
                }
452

    
453
                if (getLayer().TestCapability(ogrConstants.OLCTransactions)) {
454
                    getLayer().CommitTransaction();
455
                }
456
                getDataSource().SyncToDisk();
457
                repack();
458
                getResource().notifyChanges();
459

    
460
                return null;
461
            }
462
        });
463
    }
464

    
465
    protected void repack() throws OGRUnsupportedFormatException {
466
        LOG.debug("Running SQL: REPACK ".concat(getLayer().GetName()));
467
        getDataSource().ExecuteSQL("REPACK ".concat(getLayer().GetName()));
468
    }
469

    
470
    @Override
471
    public Object createNewOID() {
472
        try {
473
            return getFeatureCount() + 1;
474
        } catch (DataException e) {
475
            LOG.error("Can't get feature count", e);
476
            throw new ReadRuntimeException(getFullName(), e);
477
        }
478
    }
479

    
480
    @Override
481
    public FeatureSetProvider createSet(FeatureQuery query, FeatureType featureType)
482
        throws DataException {
483
        open();
484
        return new OGRFetureSetProvider(this, query, featureType);
485
    }
486

    
487
    @Override
488
    public long getFeatureCount() throws DataException {
489
        open();
490
        return ((Number) getResource().execute(new ResourceAction() {
491

    
492
            @Override
493
            public Object run() throws Exception {
494

    
495
                int featureCount = getLayer().GetFeatureCount(0);
496
                if( featureCount == -1 ) {
497
                    featureCount = getLayer().GetFeatureCount();
498
                }
499
                return featureCount;
500
            }
501
        })).longValue();
502
    }
503

    
504
    @Override
505
    public int getOIDType() {
506
        return DataTypes.LONG;
507
    }
508

    
509
    @Override
510
    protected FeatureProvider internalGetFeatureProviderByReference(
511
        FeatureReferenceProviderServices providerServices, FeatureType featureType)
512
        throws DataException {
513

    
514
        int oid = (int)providerServices.getOID();
515
        // Parece que hay un bug en el proveedor de SQLite para gdal.
516
        // Cuando se lee la capa, el m?todo GetFID est? indexado empezando por 0,
517
        // pero cuando se busca una ogrFeature a partir de dicho FID
518
        // el m?todo GetFeature(fid) est? indexado empezando por 1.
519
        // Esto es para rodear el problema.
520
        if(this.dataSource.GetDriver().getName().equalsIgnoreCase("SQLite")){
521
            oid++;
522
        }
523
        Feature ogrFeature = getLayer().GetFeature(oid);
524
        int fid = ogrFeature.GetFID();
525
        FeatureProvider featureProvider =
526
            new DefaultFeatureProvider(featureType, fid);
527
        OGRConverter converter = new OGRConverter();
528
        featureProvider = converter.convert(featureProvider, featureType, ogrFeature);
529
        return featureProvider;
530
    }
531

    
532
    private OGRDataStoreParameters getOGRParameters() {
533
        return (OGRDataStoreParameters) this.getParameters();
534
    }
535

    
536
    @SuppressWarnings("rawtypes")
537
    protected String compoundSelect(FeatureType type, Evaluator evaluator,
538
        FeatureQueryOrder featureQueryOrder) {
539

    
540
        StringBuilder query = new StringBuilder();
541
        query.append("SELECT ");
542
        FeatureAttributeDescriptor[] attributeDescriptors = type.getAttributeDescriptors();
543
        for (int i = 0; i < attributeDescriptors.length; i++) {
544
            query.append("\"");
545
            query.append(attributeDescriptors[i].getName());
546
            query.append("\"");
547
            // Don't add the last comma
548
            if (i < attributeDescriptors.length - 1) {
549
                query.append(",");
550
            }
551
        }
552

    
553
        query.append(" FROM ");
554
        query.append("\"");
555
        query.append(getOGRParameters().getLayerName());
556
        query.append("\"");
557

    
558
        if (featureQueryOrder != null && featureQueryOrder.iterator().hasNext()) {
559
            query.append(" ORDER BY ");
560
            Iterator iterator = featureQueryOrder.iterator();
561
            while (iterator.hasNext()) {
562
                FeatureQueryOrderMember member = (FeatureQueryOrderMember) iterator.next();
563

    
564
                if (member.hasEvaluator()) {
565
                    // TODO
566
                } else {
567
                    query.append("\"");
568
                    query.append(member.getAttributeName());
569
                    query.append("\"");
570
                }
571
                if (member.getAscending()) {
572
                    query.append(" ASC");
573
                } else {
574
                    query.append(" DESC");
575
                }
576
                if (iterator.hasNext()) {
577
                    query.append(", ");
578
                } else {
579
                    query.append(' ');
580
                    break;
581
                }
582
            }
583
        }
584

    
585
        return query.toString();
586
    }
587

    
588
    @Override
589
    protected void doDispose() throws BaseException {
590
        super.doDispose();
591
        getResource().removeConsumer(this);
592
        this.resourceProvider = null;
593
        getDataSource().delete();
594
        this.envelope = null;
595
        this.newLayer = null;
596
        this.dataSource = null;
597
        this.opened = false;
598
        this.updateSupport = null;
599
    }
600

    
601
    @Override
602
    public boolean closeResourceRequested(ResourceProvider resource) {
603

    
604
        try {
605
            getDataSource().delete();
606
        } catch (OGRUnsupportedFormatException e) {
607
            LOG.warn(String.format("Can not close resource requested %1s", resource), e);
608
        }
609
        this.envelope = null;
610
        this.newLayer = null;
611
        this.dataSource = null;
612
        this.opened = false;
613
        this.updateSupport = null;
614
        return true;
615
    }
616

    
617
    @Override
618
    public void resourceChanged(ResourceProvider resource) {
619

    
620
        try {
621
            getDataSource().delete();
622
        } catch (OGRUnsupportedFormatException e) {
623
            LOG.warn(String.format("Can not close resource requested %1s", resource), e);
624
        }
625
        this.envelope = null;
626
        this.newLayer = null;
627
        this.dataSource = null;
628
        this.opened = false;
629
        this.updateSupport = null;
630
    }
631
}