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.shp / src / main / java / org / gvsig / fmap / dal / store / shp / SHPStoreProvider.java @ 40596

History | View | Annotate | Download (18.3 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

    
25
package org.gvsig.fmap.dal.store.shp;
26

    
27
import java.io.File;
28
import java.io.IOException;
29
import java.util.Iterator;
30

    
31
import org.apache.commons.io.FileUtils;
32
import org.cresques.cts.IProjection;
33
import org.slf4j.Logger;
34
import org.slf4j.LoggerFactory;
35

    
36
import org.gvsig.fmap.dal.DataStore;
37
import org.gvsig.fmap.dal.DataTypes;
38
import org.gvsig.fmap.dal.FileHelper;
39
import org.gvsig.fmap.dal.exception.CloseException;
40
import org.gvsig.fmap.dal.exception.DataException;
41
import org.gvsig.fmap.dal.exception.InitializeException;
42
import org.gvsig.fmap.dal.exception.OpenException;
43
import org.gvsig.fmap.dal.exception.ReadException;
44
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
45
import org.gvsig.fmap.dal.feature.EditableFeatureType;
46
import org.gvsig.fmap.dal.feature.Feature;
47
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
48
import org.gvsig.fmap.dal.feature.FeatureSet;
49
import org.gvsig.fmap.dal.feature.FeatureStore;
50
import org.gvsig.fmap.dal.feature.FeatureType;
51
import org.gvsig.fmap.dal.feature.exception.PerformEditingException;
52
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
53
import org.gvsig.fmap.dal.resource.ResourceAction;
54
import org.gvsig.fmap.dal.resource.exception.ResourceException;
55
import org.gvsig.fmap.dal.resource.exception.ResourceExecuteException;
56
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyChangesException;
57
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyCloseException;
58
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyOpenException;
59
import org.gvsig.fmap.dal.resource.file.FileResource;
60
import org.gvsig.fmap.dal.resource.spi.MultiResource;
61
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
62
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
63
import org.gvsig.fmap.dal.store.dbf.DBFStoreParameters;
64
import org.gvsig.fmap.dal.store.dbf.DBFStoreProvider;
65
import org.gvsig.fmap.dal.store.shp.utils.SHPFile;
66
import org.gvsig.fmap.geom.Geometry;
67
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
68
import org.gvsig.fmap.geom.GeometryLocator;
69
import org.gvsig.fmap.geom.GeometryManager;
70
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
71
import org.gvsig.fmap.geom.exception.CreateGeometryException;
72
import org.gvsig.fmap.geom.primitive.Envelope;
73
import org.gvsig.tools.dispose.DisposableIterator;
74
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
75
import org.gvsig.tools.exception.BaseException;
76

    
77
public class SHPStoreProvider extends DBFStoreProvider {
78
        private static final GeometryManager geomManager = GeometryLocator.getGeometryManager();
79
        private static final Logger logger = LoggerFactory.getLogger(GeometryManager.class);
80
        public static String NAME = "Shape";
81
        public static String DESCRIPTION = "Shape file";
82
        private SHPFile shpFile;
83

    
84
        private MultiResource resource;
85

    
86
        protected static final String GEOMETRY_ATTIBUTE_NAME = "GEOMETRY";
87

    
88
        public static final String METADATA_DEFINITION_NAME = NAME;
89

    
90
        private SHPFeatureWriter writer = null;
91

    
92
        public SHPStoreProvider(SHPStoreParameters params,
93
                        DataStoreProviderServices storeServices)
94
                        throws InitializeException {
95
                super(
96
                        params, 
97
                        storeServices,
98
                        FileHelper.newMetadataContainer(METADATA_DEFINITION_NAME)
99
                );
100
        }
101

    
102
        protected void init(DBFStoreParameters params,
103
                        DataStoreProviderServices storeServices) throws InitializeException {
104

    
105
                this.shpFile = new SHPFile((SHPStoreParameters) params);
106
                super.init(params, storeServices);
107
        }
108

    
109
        public Object getDynValue(String name) throws DynFieldNotFoundException {
110
                if( DataStore.METADATA_CRS.equalsIgnoreCase(name) ) {
111
                    
112
                        /*
113
                         * String srs =  this.shpFile.getSRSParameters();
114
                        if (srs != null){
115
                        // This can be non null but not sure how to handle
116
                        }
117
                        */
118
                        return this.getShpParameters().getCRS();
119
                        
120
                } else if( DataStore.METADATA_ENVELOPE.equalsIgnoreCase(name) ) {
121
                        try {
122
                                return this.shpFile.getFullExtent();
123
                        } catch (ReadException e) {
124
                                return null;
125
                        }
126
                }
127
                return super.getDynValue(name);
128
        }
129
        
130
        protected void initResource(DBFStoreParameters params,
131
                        DataStoreProviderServices storeServices) throws InitializeException {
132

    
133
                SHPStoreParameters shpParams = (SHPStoreParameters) params;
134
                resource =
135
                                (MultiResource) createResource(MultiResource.TYPE_NAME,
136
                                                new Object[] { shpParams.getSHPFileName() });
137

    
138
                resource.addResource(FileResource.NAME,
139
                                new Object[] { shpParams.getSHPFileName() }, true);
140
                resource.addResource(FileResource.NAME,
141
                                new Object[] { shpParams.getSHXFileName() }, true);
142
                resource.addResource(FileResource.NAME,
143
                                new Object[] { shpParams.getDBFFileName() }, true);
144

    
145
                resource.addConsumer(this);
146
        };
147

    
148
        public ResourceProvider getResource() {
149
                return resource;
150
        }
151

    
152
        /**
153
         *
154
         * @throws ResourceNotifyChangesException
155
         */
156
        protected void resourcesNotifyChanges()
157
                        throws ResourceNotifyChangesException {
158
                // super.resourcesNotifyChanges();
159
                // this.shpResource.notifyChanges();
160
                // this.shxResource.notifyChanges();
161
                getResource().notifyChanges();
162
                // TODO .prj
163

    
164
        }
165

    
166
        /**
167
         * @throws ResourceNotifyCloseException
168
         *
169
         */
170
        protected void resourcesNotifyClose() throws ResourceNotifyCloseException {
171
//                super.resourcesNotifyClose();
172
//                this.shpResource.notifyClose();
173
//                this.shxResource.notifyClose();
174
                getResource().notifyClose();
175
                // TODO .prj
176

    
177
        }
178

    
179
        @Override
180
        protected void doDispose() throws BaseException {
181
                super.doDispose();
182
                getResource().removeConsumer(this);
183
                this.writer = null;
184
                this.shpFile = null;
185
        }
186

    
187
        protected void disposeResource() {
188
                getResource().removeConsumer(this);
189
        }
190

    
191
        /**
192
         * @throws ResourceNotifyOpenException
193
         *
194
         */
195
        protected void resourcesOpen() throws ResourceNotifyOpenException {
196
                // super.resourcesOpen();
197
                // this.shpResource.notifyOpen();
198
                // this.shxResource.notifyOpen();
199
                getResource().notifyOpen();
200
        }
201

    
202
        protected static EditableFeatureAttributeDescriptor addGeometryColumn(
203
                        EditableFeatureType fType) {
204

    
205
                EditableFeatureAttributeDescriptor attrTmp = null;
206
                EditableFeatureAttributeDescriptor attr = null;
207
                Iterator iter = fType.iterator();
208
                while (iter.hasNext()) {
209
                        attrTmp = (EditableFeatureAttributeDescriptor) iter.next();
210
                        if (attrTmp.getType() == DataTypes.GEOMETRY) {
211
                                if (attr != null) {
212
                                        // Two geom fields not allowed
213
                                        fType.remove(attrTmp.getName());
214
                                } else {
215
                                        attr = attrTmp;
216
                                        attr.setName(GEOMETRY_ATTIBUTE_NAME);
217
                                }
218
                        }
219
                }
220

    
221

    
222
                if (attr == null){
223
                        attr = fType.add(
224
                                        GEOMETRY_ATTIBUTE_NAME, DataTypes.GEOMETRY);
225
                        try {
226
                                attr.setDefaultValue(geomManager
227
                                                .createNullGeometry(SUBTYPES.GEOM2D));
228
                        } catch (CreateGeometryException e) {
229
                                logger.error("Error creating the envelope", e);
230
                        }
231
                }
232

    
233
                attr.setObjectClass(Geometry.class);                
234
                fType.setDefaultGeometryAttributeName(attr.getName());
235
                return attr;
236

    
237
        }
238

    
239
        protected static FeatureType removeGeometryColumn(
240
                        EditableFeatureType fType) {
241
                Iterator iter = fType.iterator();
242
                FeatureAttributeDescriptor attr;
243
                while (iter.hasNext()) {
244
                        attr = (FeatureAttributeDescriptor) iter.next();
245
                        if (attr.getType() == DataTypes.GEOMETRY) {
246
                                iter.remove();
247
                        }
248
                }
249
                fType.setDefaultGeometryAttributeName(null);
250
                return fType.getNotEditableCopy();
251
        }
252

    
253
        protected EditableFeatureType getTheFeatureType()
254
                        throws InitializeException, OpenException {
255
                final EditableFeatureType fType = super.getTheFeatureType();
256
                this.open();
257
                // try {
258
                // this.resourcesBegin();
259
                // } catch (DataException e) {
260
                // throw new InitializeException(this.getName(), e);
261
                // }
262
                try {
263
                        getResource().execute(new ResourceAction() {
264
                                public Object run() throws Exception {
265
                                        EditableFeatureAttributeDescriptor attr =
266
                                                        addGeometryColumn(fType);
267
                                        attr.setGeometryType(shpFile.getGeometryType());
268
                                        attr.setGeometrySubType(shpFile.getGeometrySubType());
269

    
270
                                        IProjection srs = getShpParameters().getCRS();
271
                                        attr.setSRS(srs);
272

    
273
                                        return null;
274
                                }
275
                        });
276
                        return fType;
277
                } catch (ResourceExecuteException e) {
278
                        throw new InitializeException(e);
279
                        // } finally {
280
                        // this.resourcesEnd();
281
                }
282
        }
283

    
284
//        private String getSRSFromPrj(String srsParameters) {
285
//                // TODO identificar que SRS hay que usar, ya sea
286
//                // el que se recibe de los parametros o el que
287
//                // conicida con el que se ha encontrado en el
288
//                // prg... y si ninguna de las dos que?
289
//                return null;
290
//        }
291

    
292
        protected SHPStoreParameters getShpParameters() {
293
                return (SHPStoreParameters) getParameters();
294
        }
295

    
296
        public String getProviderName() {
297
                return NAME;
298
        }
299

    
300
        public boolean allowWrite() {
301
                return this.shpFile.isEditable();
302
        }
303

    
304
        /**
305
         *
306
         * @param index
307
         * @param featureType
308
         * @return
309
         * @throws ReadException
310
         */
311
        protected FeatureProvider getFeatureProviderByIndex(long index,
312
                        FeatureType featureType) throws DataException {
313
                // this.open();
314
                // this.resourcesBegin();
315
                try {
316

    
317
                        FeatureProvider featureProvider = super.getFeatureProviderByIndex(index,
318
                                        featureType);
319
                        featureProvider.setDefaultEnvelope(this.shpFile.getBoundingBox(index));
320
                        return featureProvider;
321
                } catch (DataException e) {
322
                        throw e;
323
                } catch (CreateEnvelopeException e) {
324
                        throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);                
325
                } catch (CreateGeometryException e) {
326
                    throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);
327
        }
328

    
329
        }
330

    
331
        protected void initFeatureProviderByIndex(FeatureProvider featureProvider,
332
                        long index, FeatureType featureType) throws DataException {
333
                // this.open();
334
                // this.resourcesBegin();
335
                try {
336
                        super.initFeatureProviderByIndex(featureProvider, index, featureType);
337
                        featureProvider.setDefaultEnvelope(this.shpFile.getBoundingBox(index));
338
                } catch (CreateEnvelopeException e) {
339
                        throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);                        
340
                } catch (CreateGeometryException e) {
341
                    throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);       
342
        }
343
        }
344

    
345
        /**
346
         *
347
         * @param featureProvider
348
         * @throws DataException
349
         */
350
        protected void loadFeatureProviderByIndex(FeatureProvider featureProvider)
351
                        throws DataException {
352
                // this.open();
353
                // this.resourcesBegin();
354
                // try {
355
                        FeatureType featureType = featureProvider.getType();
356
                        long index = ((Long) featureProvider.getOID()).longValue();
357
                        boolean hasGeometry = false;
358
                        if (featureType.getIndex(featureType.getDefaultGeometryAttributeName()) >= 0) {
359
                                try {
360
                                        featureProvider.setDefaultGeometry(this.shpFile.getGeometry(index));
361
                                        hasGeometry = true;
362
                                } catch (CreateGeometryException e) {
363
                                        throw new ReadException(getProviderName(), e);
364
                                }
365
                        }
366
                        if (hasDBFAttributes(featureType, hasGeometry)) {
367
                                super.loadFeatureProviderByIndex(featureProvider);
368
                        }
369

    
370
                // } finally {
371
                // this.resourcesEnd();
372
                // }
373

    
374
        }
375

    
376
        private boolean hasDBFAttributes(FeatureType featureType,
377
                        boolean hasGeometry) {
378
                FeatureAttributeDescriptor[] attributes =
379
                                featureType.getAttributeDescriptors();
380
                // If there aren't any attributes, nor has any DBF attributes
381
                if (attributes == null || attributes.length == 0) {
382
                        return false;
383
                }
384
                // If there is only one attribute and it is the geometry one
385
                if (attributes.length == 1 && hasGeometry) {
386
                        return false;
387
                }
388
                // In any other case
389
                return true;
390
        }
391

    
392
        protected void loadValue(FeatureProvider featureProvider, int rowIndex,
393
                        FeatureAttributeDescriptor descriptor) throws ReadException {
394
                if (descriptor.getType() == DataTypes.GEOMETRY) {
395
                        return;
396
                } else {
397
                        super.loadValue(featureProvider, rowIndex, descriptor);
398
                }
399
        }
400

    
401
        public FeatureProvider createFeatureProvider(FeatureType type) throws DataException {
402
                FeatureProvider data = new SHPFeatureProvider(this, type);
403
                return data;
404
        }
405

    
406

    
407
        protected void openFile() throws IOException, DataException {
408
                super.openFile();
409
                this.shpFile.open();
410

    
411
        }
412

    
413
        protected void closeFile() throws CloseException {
414
                super.closeFile();
415
                if (!this.shpFile.isOpen()) {
416
                        return;
417
                }
418
                this.shpFile.close();
419
        }
420

    
421
        public boolean canWriteGeometry(final int geometryType, int geometrySubType)
422
                        throws DataException {
423
                this.open();
424
                return ((Boolean) getResource().execute(new ResourceAction() {
425
                        public Object run() throws Exception {
426
                                boolean value = shpFile.canWriteGeometry(geometryType);
427
                                return value ? Boolean.TRUE : Boolean.FALSE;
428
                        }
429
                })).booleanValue();
430
//                this.resourcesBegin();
431
//                try {
432
//                        return this.shpFile.canWriteGeometry(geometryType);
433
//
434
//                } finally {
435
//                        this.resourcesEnd();
436
//                }
437
        }
438

    
439
        public void performChanges(Iterator deleteds, Iterator inserteds,
440
                        Iterator updateds, Iterator originalFeatureTypesUpdated) throws PerformEditingException {
441
                final FeatureType fType;
442
                try {
443
                        fType = this.getStoreServices().getDefaultFeatureType();
444
                } catch (DataException e) {
445
                        throw new PerformEditingException(this.getProviderName(), e);
446
                }
447
                // TODO Comprobar el campo de geometria
448

    
449
                final EditableFeatureType dbfFtype = fType.getEditable();
450

    
451
                removeGeometryColumn(dbfFtype);
452

    
453
                // try {
454
                // this.resourcesBegin();
455
                // } catch (ResourceExecuteException e1) {
456
                // throw new PerformEditingException(this.getName(), e1);
457
                // }
458

    
459
                try {
460

    
461
                        getResource().execute(new ResourceAction() {
462
                                public Object run() throws Exception {
463
                                        FeatureSet set = null;
464
                                        DisposableIterator iter = null;
465
                                        try {
466
                                                set = getFeatureStore().getFeatureSet();
467
                                                writer = new SHPFeatureWriter(getProviderName());
468

    
469
                                                SHPStoreParameters shpParams = getShpParameters();
470
                                                SHPStoreParameters tmpParams =
471
                                                                (SHPStoreParameters) shpParams.getCopy();
472
                                                
473
                                                File tmp_base = File.createTempFile(
474
                                                    "tmp_" + System.currentTimeMillis(), null);
475
                                                String str_base = tmp_base.getCanonicalPath();
476
                                                
477
                                                tmpParams.setDBFFile(str_base + ".dbf");
478
                                                tmpParams.setSHPFile(str_base + ".shp");
479
                                                tmpParams.setSHXFile(str_base + ".shx");
480

    
481
                                                writer.begin(tmpParams, fType, dbfFtype, set.getSize());
482

    
483
                                                iter = set.fastIterator();
484
                                                while (iter.hasNext()) {
485
                                                        Feature feature = (Feature) iter.next();
486
                                                        writer.append(feature);
487
                                                }
488

    
489
                                                writer.end();
490

    
491
                                                close();
492
                                                resourceCloseRequest();
493

    
494
                                                if (!shpParams.getDBFFile().delete()) {
495
                                                        throw new PerformEditingException(getProviderName(),
496
                                                                        new IOException(shpParams.getDBFFileName()));
497
                                                }
498
                                                if (!shpParams.getSHPFile().delete()) {
499
                                                        throw new PerformEditingException(getProviderName(),
500
                                                                        new IOException(shpParams.getSHPFileName()));
501
                                                }
502
                                                if (!shpParams.getSHXFile().delete()) {
503
                                                        throw new PerformEditingException(getProviderName(),
504
                                                                        new IOException(shpParams.getSHXFileName()));
505
                                                }
506
                                                
507
                                                if (!tmpParams.getDBFFile().renameTo(
508
                                                                shpParams.getDBFFile())) {
509
                                                    logger.info("Warning: copying tmp file instead of renaming: "
510
                                                        + shpParams.getDBFFile());
511
                                                    FileUtils.copyFile(
512
                                                        tmpParams.getDBFFile(),
513
                                                        shpParams.getDBFFile());
514
                                                }
515
                                                if (!tmpParams.getSHPFile().renameTo(
516
                                                                shpParams.getSHPFile())) {
517
                            logger.info("Warning: copying tmp file instead of renaming: "
518
                                + shpParams.getSHPFile());
519
                            FileUtils.copyFile(
520
                                tmpParams.getSHPFile(),
521
                                shpParams.getSHPFile());
522
                                                }
523
                                                if (!tmpParams.getSHXFile().renameTo(
524
                                                                shpParams.getSHXFile())) {
525
                            logger.info("Warning: copying tmp file instead of renaming: "
526
                                + shpParams.getSHXFile());
527
                            FileUtils.copyFile(
528
                                tmpParams.getSHXFile(),
529
                                shpParams.getSHXFile());
530
                                                }
531

    
532
                                                resourcesNotifyChanges();
533
                                                initFeatureType();
534
                                                return null;
535
                                        } finally {
536
                                                dispose(set);
537
                                                dispose(iter);
538
                                        }
539
                                }
540
                        });
541

    
542
                } catch (Exception e) {
543
                        throw new PerformEditingException(this.getProviderName(), e);
544
                        // } finally {
545
                        // this.resourcesEnd();
546
                }
547

    
548

    
549
        }
550

    
551
        protected void resourceCloseRequest() throws ResourceException {
552
                // super.resourceCloseRequest();
553
                // this.shpResource.closeRequest();
554
                // this.shxResource.closeRequest();
555
                getResource().closeRequest();
556
        }
557

    
558
        public Envelope getEnvelope() throws DataException {
559
                this.open();
560
                return (Envelope) this.getDynValue("Envelope");
561
        }
562

    
563
        public void append(final FeatureProvider featureProvider) throws DataException {
564
//                this.resourcesBegin();
565
//                try {
566

    
567
                getResource().execute(new ResourceAction() {
568
                        public Object run() throws Exception {
569
                                writer.append(getStoreServices().createFeature(featureProvider));
570
                                return null;
571
                        }
572
                });
573
//                } finally {
574
//                        this.resourcesEnd();
575
//                }
576

    
577
        }
578

    
579
        public void beginAppend() throws DataException {
580
                // this.resourcesBegin();
581
                // try {
582

    
583
                getResource().execute(new ResourceAction() {
584
                        public Object run() throws Exception {
585
                                FeatureStore store = getFeatureStore();
586
                                FeatureType fType = store.getDefaultFeatureType();
587

    
588
                                // TODO Comprobar el campo de geometria
589

    
590
                                EditableFeatureType dbfFtype = fType.getEditable();
591

    
592
                                removeGeometryColumn(dbfFtype);
593
                                FeatureSet set = store.getFeatureSet();
594

    
595
                                writer = new SHPFeatureWriter(getProviderName());
596

    
597
                                writer.begin(getShpParameters(), fType, dbfFtype, set.getSize());
598
                                return null;
599
                        }
600
                });
601
                // } finally {
602
                // this.resourcesEnd();
603
                // }
604

    
605
        }
606

    
607
        public void endAppend() throws DataException {
608
//                this.resourcesBegin();
609
//                try {
610
                getResource().execute(new ResourceAction() {
611
                        public Object run() throws Exception {
612
                                writer.end();
613
                                resourcesNotifyChanges();
614
                                return null;
615
                        }
616
                });
617
//                } finally {
618
//                        this.resourcesEnd();
619
//                }
620

    
621
        }
622

    
623
        public Object getSourceId() {
624
                return this.getShpParameters().getFile();
625
        }
626
}