Statistics
| Revision:

svn-gvsig-desktop / branches / v2_0_0_prep / libraries / libFMap_dalfile / src / org / gvsig / fmap / dal / store / shp / SHPStoreProvider.java @ 39619

History | View | Annotate | Download (18.6 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 */
22

    
23
/*
24
* AUTHORS (In addition to CIT):
25
* 2008 IVER T.I. S.A.   {{Task}}
26
*/
27

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

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

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

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

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

    
89
        private MultiResource resource;
90

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

    
93
        public static final String METADATA_DEFINITION_NAME = NAME;
94

    
95
        private SHPFeatureWriter writer = null;
96

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

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

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

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

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

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

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

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

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

    
169
        }
170

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

    
182
        }
183

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

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

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

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

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

    
226

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

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

    
242
        }
243

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

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

    
275
                                        IProjection srs = getShpParameters().getCRS();
276
                                        if (srs == null) {
277
                                            MapContextManager mcm = MapContextLocator.getMapContextManager();
278
                                                srs = mcm.getDefaultCRS();
279
                                        }
280

    
281
                                        attr.setSRS(srs);
282

    
283
                                        return null;
284
                                }
285
                        });
286
                        return fType;
287
                } catch (ResourceExecuteException e) {
288
                        throw new InitializeException(e);
289
                        // } finally {
290
                        // this.resourcesEnd();
291
                }
292
        }
293

    
294
//        private String getSRSFromPrj(String srsParameters) {
295
//                // TODO identificar que SRS hay que usar, ya sea
296
//                // el que se recibe de los parametros o el que
297
//                // conicida con el que se ha encontrado en el
298
//                // prg... y si ninguna de las dos que?
299
//                return null;
300
//        }
301

    
302
        protected SHPStoreParameters getShpParameters() {
303
                return (SHPStoreParameters) getParameters();
304
        }
305

    
306
        public String getProviderName() {
307
                return NAME;
308
        }
309

    
310
        public boolean allowWrite() {
311
                return this.shpFile.isEditable();
312
        }
313

    
314
        /**
315
         *
316
         * @param index
317
         * @param featureType
318
         * @return
319
         * @throws ReadException
320
         */
321
        protected FeatureProvider getFeatureProviderByIndex(long index,
322
                        FeatureType featureType) throws DataException {
323
                // this.open();
324
                // this.resourcesBegin();
325
                try {
326

    
327
                        FeatureProvider featureProvider = super.getFeatureProviderByIndex(index,
328
                                        featureType);
329
                        featureProvider.setDefaultEnvelope(this.shpFile.getBoundingBox(index));
330
                        return featureProvider;
331
                } catch (DataException e) {
332
                        throw e;
333
                } catch (CreateEnvelopeException e) {
334
                        throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);                
335
                } catch (CreateGeometryException e) {
336
                    throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);
337
        }
338

    
339
        }
340

    
341
        protected void initFeatureProviderByIndex(FeatureProvider featureProvider,
342
                        long index, FeatureType featureType) throws DataException {
343
                // this.open();
344
                // this.resourcesBegin();
345
                try {
346
                        super.initFeatureProviderByIndex(featureProvider, index, featureType);
347
                        featureProvider.setDefaultEnvelope(this.shpFile.getBoundingBox(index));
348
                } catch (CreateEnvelopeException e) {
349
                        throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);                        
350
                } catch (CreateGeometryException e) {
351
                    throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);       
352
        }
353
        }
354

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

    
380
                // } finally {
381
                // this.resourcesEnd();
382
                // }
383

    
384
        }
385

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

    
402
        protected void loadValue(FeatureProvider featureProvider, int rowIndex,
403
                        FeatureAttributeDescriptor descriptor) throws ReadException {
404
                if (descriptor.getType() == DataTypes.GEOMETRY) {
405
                        return;
406
                } else {
407
                        super.loadValue(featureProvider, rowIndex, descriptor);
408
                }
409
        }
410

    
411
        public FeatureProvider createFeatureProvider(FeatureType type) throws DataException {
412
                FeatureProvider data = new SHPFeatureProvider(this, type);
413
                return data;
414
        }
415

    
416

    
417
        protected void openFile() throws IOException, DataException {
418
                super.openFile();
419
                this.shpFile.open();
420

    
421
        }
422

    
423
        protected void closeFile() throws CloseException {
424
                super.closeFile();
425
                if (!this.shpFile.isOpen()) {
426
                        return;
427
                }
428
                this.shpFile.close();
429
        }
430

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

    
449
        public void performChanges(Iterator deleteds, Iterator inserteds,
450
                        Iterator updateds, Iterator originalFeatureTypesUpdated) throws PerformEditingException {
451
                final FeatureType fType;
452
                try {
453
                        fType = this.getStoreServices().getDefaultFeatureType();
454
                } catch (DataException e) {
455
                        throw new PerformEditingException(this.getProviderName(), e);
456
                }
457
                // TODO Comprobar el campo de geometria
458

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

    
461
                removeGeometryColumn(dbfFtype);
462

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

    
469
                try {
470

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

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

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

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

    
499
                                                writer.end();
500

    
501
                                                close();
502
                                                resourceCloseRequest();
503

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

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

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

    
558

    
559
        }
560

    
561
        protected void resourceCloseRequest() throws ResourceException {
562
                // super.resourceCloseRequest();
563
                // this.shpResource.closeRequest();
564
                // this.shxResource.closeRequest();
565
                getResource().closeRequest();
566
        }
567

    
568
        public Envelope getEnvelope() throws DataException {
569
                this.open();
570
                return (Envelope) this.getDynValue("Envelope");
571
        }
572

    
573
        public void append(final FeatureProvider featureProvider) throws DataException {
574
//                this.resourcesBegin();
575
//                try {
576

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

    
587
        }
588

    
589
        public void beginAppend() throws DataException {
590
                // this.resourcesBegin();
591
                // try {
592

    
593
                getResource().execute(new ResourceAction() {
594
                        public Object run() throws Exception {
595
                                FeatureStore store = getFeatureStore();
596
                                FeatureType fType = store.getDefaultFeatureType();
597

    
598
                                // TODO Comprobar el campo de geometria
599

    
600
                                EditableFeatureType dbfFtype = fType.getEditable();
601

    
602
                                removeGeometryColumn(dbfFtype);
603
                                FeatureSet set = store.getFeatureSet();
604

    
605
                                writer = new SHPFeatureWriter(getProviderName());
606

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

    
615
        }
616

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

    
631
        }
632

    
633
        public Object getSourceId() {
634
                return this.getShpParameters().getFile();
635
        }
636
}