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

History | View | Annotate | Download (18.5 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.AttributeNameException;
52
import org.gvsig.fmap.dal.feature.exception.PerformEditingException;
53
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
54
import org.gvsig.fmap.dal.resource.ResourceAction;
55
import org.gvsig.fmap.dal.resource.exception.ResourceException;
56
import org.gvsig.fmap.dal.resource.exception.ResourceExecuteException;
57
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyChangesException;
58
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyCloseException;
59
import org.gvsig.fmap.dal.resource.exception.ResourceNotifyOpenException;
60
import org.gvsig.fmap.dal.resource.file.FileResource;
61
import org.gvsig.fmap.dal.resource.spi.MultiResource;
62
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
63
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
64
import org.gvsig.fmap.dal.store.dbf.DBFStoreParameters;
65
import org.gvsig.fmap.dal.store.dbf.DBFStoreProvider;
66
import org.gvsig.fmap.dal.store.shp.utils.SHPFile;
67
import org.gvsig.fmap.geom.Geometry;
68
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
69
import org.gvsig.fmap.geom.GeometryLocator;
70
import org.gvsig.fmap.geom.GeometryManager;
71
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
72
import org.gvsig.fmap.geom.exception.CreateGeometryException;
73
import org.gvsig.fmap.geom.primitive.Envelope;
74
import org.gvsig.tools.dispose.DisposableIterator;
75
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
76
import org.gvsig.tools.exception.BaseException;
77

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

    
85
        private MultiResource resource;
86

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

    
89
        public static final String METADATA_DEFINITION_NAME = NAME;
90

    
91
        private SHPFeatureWriter writer = null;
92

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

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

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

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

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

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

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

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

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

    
165
        }
166

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

    
178
        }
179

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

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

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

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

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

    
222

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

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

    
238
        }
239

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

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

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

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

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

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

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

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

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

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

    
330
        }
331

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

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

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

    
375
        }
376

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

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

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

    
407

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

    
412
        }
413

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

    
422
        public boolean canWriteGeometry(final int geometryType, int geometrySubType)
423
                        throws DataException {
424
                this.open();
425
                return ((Boolean) getResource().execute(new ResourceAction() {
426
                        public Object run() throws Exception {
427
                                boolean value = shpFile.canWriteGeometry(geometryType);
428
                                return value ? Boolean.TRUE : Boolean.FALSE;
429
                        }
430
                })).booleanValue();
431
//                this.resourcesBegin();
432
//                try {
433
//                        return this.shpFile.canWriteGeometry(geometryType);
434
//
435
//                } finally {
436
//                        this.resourcesEnd();
437
//                }
438
        }
439
        
440
        public void performChanges(Iterator deleteds, Iterator inserteds,
441
                        Iterator updateds, Iterator originalFeatureTypesUpdated)
442
                                        throws PerformEditingException {
443
                
444
                
445
                /*
446
                 * This will throw an exception if there are new fields
447
                 * with names too long
448
                 */
449
                checkNewFieldsNameSize(originalFeatureTypesUpdated);
450

    
451
                
452
                final FeatureType fType;
453
                try {
454
                        fType = this.getStoreServices().getDefaultFeatureType();
455
                } catch (DataException e) {
456
                        throw new PerformEditingException(this.getProviderName(), e);
457
                }
458
                // TODO Comprobar el campo de geometria
459

    
460
                final EditableFeatureType dbfFtype = fType.getEditable();
461

    
462
                removeGeometryColumn(dbfFtype);
463

    
464
                // try {
465
                // this.resourcesBegin();
466
                // } catch (ResourceExecuteException e1) {
467
                // throw new PerformEditingException(this.getName(), e1);
468
                // }
469

    
470
                try {
471

    
472
                        getResource().execute(new ResourceAction() {
473
                                public Object run() throws Exception {
474
                                        FeatureSet set = null;
475
                                        DisposableIterator iter = null;
476
                                        try {
477
                                                set = getFeatureStore().getFeatureSet();
478
                                                writer = new SHPFeatureWriter(getProviderName());
479

    
480
                                                SHPStoreParameters shpParams = getShpParameters();
481
                                                SHPStoreParameters tmpParams =
482
                                                                (SHPStoreParameters) shpParams.getCopy();
483
                                                
484
                                                File tmp_base = File.createTempFile(
485
                                                    "tmp_" + System.currentTimeMillis(), null);
486
                                                String str_base = tmp_base.getCanonicalPath();
487
                                                
488
                                                tmpParams.setDBFFile(str_base + ".dbf");
489
                                                tmpParams.setSHPFile(str_base + ".shp");
490
                                                tmpParams.setSHXFile(str_base + ".shx");
491

    
492
                                                writer.begin(tmpParams, fType, dbfFtype, set.getSize());
493

    
494
                                                iter = set.fastIterator();
495
                                                while (iter.hasNext()) {
496
                                                        Feature feature = (Feature) iter.next();
497
                                                        writer.append(feature);
498
                                                }
499

    
500
                                                writer.end();
501

    
502
                                                close();
503
                                                resourceCloseRequest();
504

    
505
                                                if (!shpParams.getDBFFile().delete()) {
506
                                                        throw new PerformEditingException(getProviderName(),
507
                                                                        new IOException(shpParams.getDBFFileName()));
508
                                                }
509
                                                if (!shpParams.getSHPFile().delete()) {
510
                                                        throw new PerformEditingException(getProviderName(),
511
                                                                        new IOException(shpParams.getSHPFileName()));
512
                                                }
513
                                                if (!shpParams.getSHXFile().delete()) {
514
                                                        throw new PerformEditingException(getProviderName(),
515
                                                                        new IOException(shpParams.getSHXFileName()));
516
                                                }
517
                                                
518
                                                if (!tmpParams.getDBFFile().renameTo(
519
                                                                shpParams.getDBFFile())) {
520
                                                    logger.info("Warning: copying tmp file instead of renaming: "
521
                                                        + shpParams.getDBFFile());
522
                                                    FileUtils.copyFile(
523
                                                        tmpParams.getDBFFile(),
524
                                                        shpParams.getDBFFile());
525
                                                }
526
                                                if (!tmpParams.getSHPFile().renameTo(
527
                                                                shpParams.getSHPFile())) {
528
                            logger.info("Warning: copying tmp file instead of renaming: "
529
                                + shpParams.getSHPFile());
530
                            FileUtils.copyFile(
531
                                tmpParams.getSHPFile(),
532
                                shpParams.getSHPFile());
533
                                                }
534
                                                if (!tmpParams.getSHXFile().renameTo(
535
                                                                shpParams.getSHXFile())) {
536
                            logger.info("Warning: copying tmp file instead of renaming: "
537
                                + shpParams.getSHXFile());
538
                            FileUtils.copyFile(
539
                                tmpParams.getSHXFile(),
540
                                shpParams.getSHXFile());
541
                                                }
542

    
543
                                                resourcesNotifyChanges();
544
                                                initFeatureType();
545
                                                return null;
546
                                        } finally {
547
                                                dispose(set);
548
                                                dispose(iter);
549
                                        }
550
                                }
551
                        });
552

    
553
                } catch (Exception e) {
554
                        throw new PerformEditingException(this.getProviderName(), e);
555
                        // } finally {
556
                        // this.resourcesEnd();
557
                }
558

    
559

    
560
        }
561

    
562

    
563

    
564
        protected void resourceCloseRequest() throws ResourceException {
565
                // super.resourceCloseRequest();
566
                // this.shpResource.closeRequest();
567
                // this.shxResource.closeRequest();
568
                getResource().closeRequest();
569
        }
570

    
571
        public Envelope getEnvelope() throws DataException {
572
                this.open();
573
                return (Envelope) this.getDynValue("Envelope");
574
        }
575

    
576
        public void append(final FeatureProvider featureProvider) throws DataException {
577
//                this.resourcesBegin();
578
//                try {
579

    
580
                getResource().execute(new ResourceAction() {
581
                        public Object run() throws Exception {
582
                                writer.append(getStoreServices().createFeature(featureProvider));
583
                                return null;
584
                        }
585
                });
586
//                } finally {
587
//                        this.resourcesEnd();
588
//                }
589

    
590
        }
591

    
592
        public void beginAppend() throws DataException {
593
                // this.resourcesBegin();
594
                // try {
595

    
596
                getResource().execute(new ResourceAction() {
597
                        public Object run() throws Exception {
598
                                FeatureStore store = getFeatureStore();
599
                                FeatureType fType = store.getDefaultFeatureType();
600

    
601
                                // TODO Comprobar el campo de geometria
602

    
603
                                EditableFeatureType dbfFtype = fType.getEditable();
604

    
605
                                removeGeometryColumn(dbfFtype);
606
                                FeatureSet set = store.getFeatureSet();
607

    
608
                                writer = new SHPFeatureWriter(getProviderName());
609

    
610
                                writer.begin(getShpParameters(), fType, dbfFtype, set.getSize());
611
                                return null;
612
                        }
613
                });
614
                // } finally {
615
                // this.resourcesEnd();
616
                // }
617

    
618
        }
619

    
620
        public void endAppend() throws DataException {
621
//                this.resourcesBegin();
622
//                try {
623
                getResource().execute(new ResourceAction() {
624
                        public Object run() throws Exception {
625
                                writer.end();
626
                                resourcesNotifyChanges();
627
                                return null;
628
                        }
629
                });
630
//                } finally {
631
//                        this.resourcesEnd();
632
//                }
633

    
634
        }
635

    
636
        public Object getSourceId() {
637
                return this.getShpParameters().getFile();
638
        }
639
}