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

History | View | Annotate | Download (18.4 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
* AUTHORS (In addition to CIT):
26
* 2008 IVER T.I. S.A.   {{Task}}
27
*/
28

    
29
package org.gvsig.fmap.dal.store.shp;
30

    
31
import java.io.File;
32
import java.io.IOException;
33
import java.util.Iterator;
34

    
35
import org.apache.commons.io.FileUtils;
36
import org.cresques.cts.IProjection;
37
import org.slf4j.Logger;
38
import org.slf4j.LoggerFactory;
39

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

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

    
88
        private MultiResource resource;
89

    
90
        protected static final String GEOMETRY_ATTIBUTE_NAME = "GEOMETRY";
91

    
92
        public static final String METADATA_DEFINITION_NAME = NAME;
93

    
94
        private SHPFeatureWriter writer = null;
95

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

    
106
        protected void init(DBFStoreParameters params,
107
                        DataStoreProviderServices storeServices) throws InitializeException {
108

    
109
                this.shpFile = new SHPFile((SHPStoreParameters) params);
110
                super.init(params, storeServices);
111
        }
112

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

    
137
                SHPStoreParameters shpParams = (SHPStoreParameters) params;
138
                resource =
139
                                (MultiResource) createResource(MultiResource.TYPE_NAME,
140
                                                new Object[] { shpParams.getSHPFileName() });
141

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

    
149
                resource.addConsumer(this);
150
        };
151

    
152
        public ResourceProvider getResource() {
153
                return resource;
154
        }
155

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

    
168
        }
169

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

    
181
        }
182

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

    
191
        protected void disposeResource() {
192
                getResource().removeConsumer(this);
193
        }
194

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

    
206
        protected static EditableFeatureAttributeDescriptor addGeometryColumn(
207
                        EditableFeatureType fType) {
208

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

    
225

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

    
237
                attr.setObjectClass(Geometry.class);                
238
                fType.setDefaultGeometryAttributeName(attr.getName());
239
                return attr;
240

    
241
        }
242

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

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

    
274
                                        IProjection srs = getShpParameters().getCRS();
275
                                        attr.setSRS(srs);
276

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

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

    
296
        protected SHPStoreParameters getShpParameters() {
297
                return (SHPStoreParameters) getParameters();
298
        }
299

    
300
        public String getProviderName() {
301
                return NAME;
302
        }
303

    
304
        public boolean allowWrite() {
305
                return this.shpFile.isEditable();
306
        }
307

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

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

    
333
        }
334

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

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

    
374
                // } finally {
375
                // this.resourcesEnd();
376
                // }
377

    
378
        }
379

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

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

    
405
        public FeatureProvider createFeatureProvider(FeatureType type) throws DataException {
406
                FeatureProvider data = new SHPFeatureProvider(this, type);
407
                return data;
408
        }
409

    
410

    
411
        protected void openFile() throws IOException, DataException {
412
                super.openFile();
413
                this.shpFile.open();
414

    
415
        }
416

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

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

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

    
453
                final EditableFeatureType dbfFtype = fType.getEditable();
454

    
455
                removeGeometryColumn(dbfFtype);
456

    
457
                // try {
458
                // this.resourcesBegin();
459
                // } catch (ResourceExecuteException e1) {
460
                // throw new PerformEditingException(this.getName(), e1);
461
                // }
462

    
463
                try {
464

    
465
                        getResource().execute(new ResourceAction() {
466
                                public Object run() throws Exception {
467
                                        FeatureSet set = null;
468
                                        DisposableIterator iter = null;
469
                                        try {
470
                                                set = getFeatureStore().getFeatureSet();
471
                                                writer = new SHPFeatureWriter(getProviderName());
472

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

    
485
                                                writer.begin(tmpParams, fType, dbfFtype, set.getSize());
486

    
487
                                                iter = set.fastIterator();
488
                                                while (iter.hasNext()) {
489
                                                        Feature feature = (Feature) iter.next();
490
                                                        writer.append(feature);
491
                                                }
492

    
493
                                                writer.end();
494

    
495
                                                close();
496
                                                resourceCloseRequest();
497

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

    
536
                                                resourcesNotifyChanges();
537
                                                initFeatureType();
538
                                                return null;
539
                                        } finally {
540
                                                dispose(set);
541
                                                dispose(iter);
542
                                        }
543
                                }
544
                        });
545

    
546
                } catch (Exception e) {
547
                        throw new PerformEditingException(this.getProviderName(), e);
548
                        // } finally {
549
                        // this.resourcesEnd();
550
                }
551

    
552

    
553
        }
554

    
555
        protected void resourceCloseRequest() throws ResourceException {
556
                // super.resourceCloseRequest();
557
                // this.shpResource.closeRequest();
558
                // this.shxResource.closeRequest();
559
                getResource().closeRequest();
560
        }
561

    
562
        public Envelope getEnvelope() throws DataException {
563
                this.open();
564
                return (Envelope) this.getDynValue("Envelope");
565
        }
566

    
567
        public void append(final FeatureProvider featureProvider) throws DataException {
568
//                this.resourcesBegin();
569
//                try {
570

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

    
581
        }
582

    
583
        public void beginAppend() throws DataException {
584
                // this.resourcesBegin();
585
                // try {
586

    
587
                getResource().execute(new ResourceAction() {
588
                        public Object run() throws Exception {
589
                                FeatureStore store = getFeatureStore();
590
                                FeatureType fType = store.getDefaultFeatureType();
591

    
592
                                // TODO Comprobar el campo de geometria
593

    
594
                                EditableFeatureType dbfFtype = fType.getEditable();
595

    
596
                                removeGeometryColumn(dbfFtype);
597
                                FeatureSet set = store.getFeatureSet();
598

    
599
                                writer = new SHPFeatureWriter(getProviderName());
600

    
601
                                writer.begin(getShpParameters(), fType, dbfFtype, set.getSize());
602
                                return null;
603
                        }
604
                });
605
                // } finally {
606
                // this.resourcesEnd();
607
                // }
608

    
609
        }
610

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

    
625
        }
626

    
627
        public Object getSourceId() {
628
                return this.getShpParameters().getFile();
629
        }
630
}